1use super::{Entity, EntityBase, EntityFindParams, EntityTransactionExt, StringEntityId};
18use crate::{connection::TransactionWrapper, CryptoKeystoreError, CryptoKeystoreResult};
19use openmls_traits::types::SignatureScheme;
20use zeroize::Zeroize;
21
22#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
24#[zeroize(drop)]
25#[cfg_attr(
26 any(target_family = "wasm", feature = "serde"),
27 derive(serde::Serialize, serde::Deserialize)
28)]
29pub struct PersistedMlsGroup {
30 pub id: Vec<u8>,
31 pub state: Vec<u8>,
32 pub parent_id: Option<Vec<u8>>,
33}
34
35#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
36#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
37pub trait PersistedMlsGroupExt: Entity {
38 fn parent_id(&self) -> Option<&[u8]>;
39
40 async fn parent_group(
41 &self,
42 conn: &mut <Self as super::EntityBase>::ConnectionType,
43 ) -> CryptoKeystoreResult<Option<Self>> {
44 let Some(parent_id) = self.parent_id() else {
45 return Ok(None);
46 };
47
48 <Self as super::Entity>::find_one(conn, &parent_id.into()).await
49 }
50
51 async fn child_groups(
52 &self,
53 conn: &mut <Self as super::EntityBase>::ConnectionType,
54 ) -> CryptoKeystoreResult<Vec<Self>> {
55 let entities = <Self as super::Entity>::find_all(conn, super::EntityFindParams::default()).await?;
56
57 let id = self.id_raw();
58
59 Ok(entities
60 .into_iter()
61 .filter(|entity| entity.parent_id().map(|parent_id| parent_id == id).unwrap_or_default())
62 .collect())
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
68#[zeroize(drop)]
69#[cfg_attr(
70 any(target_family = "wasm", feature = "serde"),
71 derive(serde::Serialize, serde::Deserialize)
72)]
73pub struct PersistedMlsPendingGroup {
74 pub id: Vec<u8>,
75 pub state: Vec<u8>,
76 pub parent_id: Option<Vec<u8>>,
77 pub custom_configuration: Vec<u8>,
78}
79
80#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
82#[zeroize(drop)]
83#[cfg_attr(
84 any(target_family = "wasm", feature = "serde"),
85 derive(serde::Serialize, serde::Deserialize)
86)]
87pub struct MlsPendingMessage {
88 pub foreign_id: Vec<u8>,
89 pub message: Vec<u8>,
90}
91
92#[derive(Debug, Clone, PartialEq, Eq, Zeroize, core_crypto_macros::Entity)]
100#[cfg_attr(
101 any(target_family = "wasm", feature = "serde"),
102 derive(serde::Serialize, serde::Deserialize)
103)]
104pub struct MlsBufferedCommit {
105 #[id(hex, column = "conversation_id_hex")]
108 conversation_id: Vec<u8>,
109 commit_data: Vec<u8>,
110}
111
112impl MlsBufferedCommit {
113 pub fn new(conversation_id: Vec<u8>, commit_data: Vec<u8>) -> Self {
115 Self {
116 conversation_id,
117 commit_data,
118 }
119 }
120
121 pub fn conversation_id(&self) -> &[u8] {
122 &self.conversation_id
123 }
124
125 pub fn commit_data(&self) -> &[u8] {
126 &self.commit_data
127 }
128
129 pub fn into_commit_data(self) -> Vec<u8> {
130 self.commit_data
131 }
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
136#[zeroize(drop)]
137#[cfg_attr(
138 any(target_family = "wasm", feature = "serde"),
139 derive(serde::Serialize, serde::Deserialize)
140)]
141pub struct MlsCredential {
142 pub id: Vec<u8>,
143 pub credential: Vec<u8>,
144 pub created_at: u64,
145}
146
147#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
148#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
149pub trait MlsCredentialExt: Entity {
150 async fn delete_by_credential(tx: &TransactionWrapper<'_>, credential: Vec<u8>) -> CryptoKeystoreResult<()>;
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
155#[zeroize(drop)]
156#[cfg_attr(
157 any(target_family = "wasm", feature = "serde"),
158 derive(serde::Serialize, serde::Deserialize)
159)]
160pub struct MlsSignatureKeyPair {
161 pub signature_scheme: u16,
162 pub pk: Vec<u8>,
163 pub keypair: Vec<u8>,
164 pub credential_id: Vec<u8>,
165}
166
167impl MlsSignatureKeyPair {
168 pub fn new(signature_scheme: SignatureScheme, pk: Vec<u8>, keypair: Vec<u8>, credential_id: Vec<u8>) -> Self {
169 Self {
170 signature_scheme: signature_scheme as u16,
171 pk,
172 keypair,
173 credential_id,
174 }
175 }
176}
177
178#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
180#[zeroize(drop)]
181#[cfg_attr(
182 any(target_family = "wasm", feature = "serde"),
183 derive(serde::Serialize, serde::Deserialize)
184)]
185pub struct MlsHpkePrivateKey {
186 pub sk: Vec<u8>,
187 pub pk: Vec<u8>,
188}
189
190#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
192#[zeroize(drop)]
193#[cfg_attr(
194 any(target_family = "wasm", feature = "serde"),
195 derive(serde::Serialize, serde::Deserialize)
196)]
197pub struct MlsEncryptionKeyPair {
198 pub sk: Vec<u8>,
199 pub pk: Vec<u8>,
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
204#[zeroize(drop)]
205#[cfg_attr(target_family = "wasm", derive(serde::Serialize, serde::Deserialize))]
206pub struct MlsEpochEncryptionKeyPair {
207 pub id: Vec<u8>,
208 pub keypairs: Vec<u8>,
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
213#[zeroize(drop)]
214#[cfg_attr(
215 any(target_family = "wasm", feature = "serde"),
216 derive(serde::Serialize, serde::Deserialize)
217)]
218pub struct MlsPskBundle {
219 pub psk_id: Vec<u8>,
220 pub psk: Vec<u8>,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
225#[zeroize(drop)]
226#[cfg_attr(
227 any(target_family = "wasm", feature = "serde"),
228 derive(serde::Serialize, serde::Deserialize)
229)]
230pub struct MlsKeyPackage {
231 pub keypackage_ref: Vec<u8>,
232 pub keypackage: Vec<u8>,
233}
234
235#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
238#[zeroize(drop)]
239#[cfg_attr(
240 any(target_family = "wasm", feature = "serde"),
241 derive(serde::Serialize, serde::Deserialize)
242)]
243pub struct E2eiEnrollment {
244 pub id: Vec<u8>,
245 pub content: Vec<u8>,
246}
247
248#[cfg(target_family = "wasm")]
249#[async_trait::async_trait(?Send)]
250pub trait UniqueEntity:
251 EntityBase<ConnectionType = crate::connection::KeystoreDatabaseConnection>
252 + serde::Serialize
253 + serde::de::DeserializeOwned
254where
255 Self: 'static,
256{
257 const ID: [u8; 1] = [0];
258
259 fn content(&self) -> &[u8];
260
261 fn set_content(&mut self, content: Vec<u8>);
262
263 async fn find_unique(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<Self> {
264 Ok(conn
265 .storage()
266 .get(Self::COLLECTION_NAME, &Self::ID)
267 .await?
268 .ok_or(CryptoKeystoreError::NotFound(Self::COLLECTION_NAME, "".to_string()))?)
269 }
270
271 async fn find_all(conn: &mut Self::ConnectionType, _params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
272 match Self::find_unique(conn).await {
273 Ok(record) => Ok(vec![record]),
274 Err(CryptoKeystoreError::NotFound(_, _)) => Ok(vec![]),
275 Err(err) => Err(err),
276 }
277 }
278
279 async fn find_one(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<Option<Self>> {
280 match Self::find_unique(conn).await {
281 Ok(record) => Ok(Some(record)),
282 Err(CryptoKeystoreError::NotFound(_, _)) => Ok(None),
283 Err(err) => Err(err),
284 }
285 }
286
287 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
288 conn.storage().count(Self::COLLECTION_NAME).await
289 }
290
291 async fn replace<'a>(&'a self, transaction: &TransactionWrapper<'a>) -> CryptoKeystoreResult<()> {
292 transaction.save(self.clone()).await?;
293 Ok(())
294 }
295}
296
297#[cfg(not(target_family = "wasm"))]
298#[async_trait::async_trait]
299pub trait UniqueEntity: EntityBase<ConnectionType = crate::connection::KeystoreDatabaseConnection> {
300 const ID: usize = 0;
301
302 fn new(content: Vec<u8>) -> Self;
303
304 async fn find_unique(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<Self> {
305 let transaction = conn.transaction()?;
306 use rusqlite::OptionalExtension as _;
307
308 let maybe_content = transaction
309 .query_row(
310 &format!("SELECT content FROM {} WHERE id = ?", Self::COLLECTION_NAME),
311 [Self::ID],
312 |r| r.get::<_, Vec<u8>>(0),
313 )
314 .optional()?;
315
316 if let Some(content) = maybe_content {
317 Ok(Self::new(content))
318 } else {
319 Err(CryptoKeystoreError::NotFound(Self::COLLECTION_NAME, "".to_string()))
320 }
321 }
322
323 async fn find_all(conn: &mut Self::ConnectionType, _params: EntityFindParams) -> CryptoKeystoreResult<Vec<Self>> {
324 match Self::find_unique(conn).await {
325 Ok(record) => Ok(vec![record]),
326 Err(CryptoKeystoreError::NotFound(_, _)) => Ok(vec![]),
327 Err(err) => Err(err),
328 }
329 }
330
331 async fn find_one(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<Option<Self>> {
332 match Self::find_unique(conn).await {
333 Ok(record) => Ok(Some(record)),
334 Err(CryptoKeystoreError::NotFound(_, _)) => Ok(None),
335 Err(err) => Err(err),
336 }
337 }
338
339 async fn count(conn: &mut Self::ConnectionType) -> CryptoKeystoreResult<usize> {
340 Ok(
341 conn.query_row(&format!("SELECT COUNT(*) FROM {}", Self::COLLECTION_NAME), [], |r| {
342 r.get(0)
343 })?,
344 )
345 }
346
347 fn content(&self) -> &[u8];
348
349 async fn replace(&self, transaction: &TransactionWrapper<'_>) -> CryptoKeystoreResult<()> {
350 use crate::connection::DatabaseConnection;
351 Self::ConnectionType::check_buffer_size(self.content().len())?;
352 let zb_content = rusqlite::blob::ZeroBlob(self.content().len() as i32);
353
354 use rusqlite::ToSql;
355 let params: [rusqlite::types::ToSqlOutput; 2] = [Self::ID.to_sql()?, zb_content.to_sql()?];
356
357 transaction.execute(
358 &format!(
359 "INSERT OR REPLACE INTO {} (id, content) VALUES (?, ?)",
360 Self::COLLECTION_NAME
361 ),
362 params,
363 )?;
364 let row_id = transaction.last_insert_rowid();
365
366 let mut blob = transaction.blob_open(
367 rusqlite::DatabaseName::Main,
368 Self::COLLECTION_NAME,
369 "content",
370 row_id,
371 false,
372 )?;
373 use std::io::Write;
374 blob.write_all(self.content())?;
375 blob.close()?;
376
377 Ok(())
378 }
379}
380
381#[cfg_attr(target_family = "wasm", async_trait::async_trait(?Send))]
382#[cfg_attr(not(target_family = "wasm"), async_trait::async_trait)]
383impl<T: UniqueEntity + Send + Sync> EntityTransactionExt for T {
384 #[cfg(not(target_family = "wasm"))]
385 async fn save(&self, tx: &TransactionWrapper<'_>) -> CryptoKeystoreResult<()> {
386 self.replace(tx).await
387 }
388
389 #[cfg(target_family = "wasm")]
390 async fn save<'a>(&'a self, tx: &TransactionWrapper<'a>) -> CryptoKeystoreResult<()> {
391 self.replace(tx).await
392 }
393
394 #[cfg(not(target_family = "wasm"))]
395 async fn delete_fail_on_missing_id(
396 _: &TransactionWrapper<'_>,
397 _id: StringEntityId<'_>,
398 ) -> CryptoKeystoreResult<()> {
399 Err(CryptoKeystoreError::NotImplemented)
400 }
401
402 #[cfg(target_family = "wasm")]
403 async fn delete_fail_on_missing_id<'a>(
404 _: &TransactionWrapper<'a>,
405 _id: StringEntityId<'a>,
406 ) -> CryptoKeystoreResult<()> {
407 Err(CryptoKeystoreError::NotImplemented)
408 }
409}
410
411#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
413#[zeroize(drop)]
414#[cfg_attr(
415 any(target_family = "wasm", feature = "serde"),
416 derive(serde::Serialize, serde::Deserialize)
417)]
418pub struct E2eiRefreshToken {
419 pub content: Vec<u8>,
420}
421
422#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
423#[zeroize(drop)]
424#[cfg_attr(
425 any(target_family = "wasm", feature = "serde"),
426 derive(serde::Serialize, serde::Deserialize)
427)]
428pub struct E2eiAcmeCA {
429 pub content: Vec<u8>,
430}
431
432#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
433#[zeroize(drop)]
434#[cfg_attr(
435 any(target_family = "wasm", feature = "serde"),
436 derive(serde::Serialize, serde::Deserialize)
437)]
438pub struct E2eiIntermediateCert {
439 pub ski_aki_pair: String,
441 pub content: Vec<u8>,
442}
443
444#[derive(Debug, Clone, PartialEq, Eq, Zeroize)]
445#[zeroize(drop)]
446#[cfg_attr(
447 any(target_family = "wasm", feature = "serde"),
448 derive(serde::Serialize, serde::Deserialize)
449)]
450pub struct E2eiCrl {
451 pub distribution_point: String,
452 pub content: Vec<u8>,
453}