core_crypto/proteus/
mod.rs1mod conversation_session;
2mod core_crypto;
3mod message;
4mod prekey;
5mod session;
6mod session_cache;
7
8use std::sync::Arc;
9
10pub use conversation_session::{ProteusConversationSession, SessionIdentifier};
11use core_crypto_keystore::{
12 Transaction,
13 entities::ProteusIdentity,
14 traits::{EntityDatabaseMutation as _, FetchFromDatabase as _},
15};
16use proteus_wasm::keys::IdentityKeyPair;
17pub(crate) use session_cache::ProteusSessionCache;
18
19use crate::{KeystoreError, ProteusError, Result};
20
21#[derive(Debug)]
27pub struct ProteusCentral {
28 proteus_identity: Arc<IdentityKeyPair>,
29 proteus_sessions: ProteusSessionCache,
30}
31
32impl ProteusCentral {
33 pub async fn try_new(transaction: &Transaction) -> Result<Self> {
35 let proteus_identity: Arc<IdentityKeyPair> = Arc::new(Self::load_or_create_identity(transaction).await?);
36 let proteus_sessions = ProteusSessionCache::new(proteus_identity.clone());
37
38 Ok(Self {
39 proteus_identity,
40 proteus_sessions,
41 })
42 }
43
44 async fn load_or_create_identity(transaction: &Transaction) -> Result<IdentityKeyPair> {
48 let Some(identity) = transaction
49 .get_unique::<ProteusIdentity>()
50 .await
51 .map_err(KeystoreError::wrap("finding proteus identity"))?
52 else {
53 return Self::create_identity(transaction).await;
54 };
55
56 let sk = identity.sk_raw();
57 let pk = identity.pk_raw();
58
59 IdentityKeyPair::from_raw_key_pair(*sk, *pk)
61 .map_err(ProteusError::wrap("constructing identity keypair"))
62 .map_err(Into::into)
63 }
64
65 async fn create_identity(transaction: &Transaction) -> Result<IdentityKeyPair> {
67 let kp = IdentityKeyPair::new();
68 let pk = kp.public_key.public_key.as_slice().to_vec();
69
70 let ks_identity = ProteusIdentity {
71 sk: kp.secret_key.to_keypair_bytes().into(),
72 pk,
73 };
74 ks_identity
75 .save(transaction)
76 .map_err(KeystoreError::wrap("saving new proteus identity"))?;
77
78 Ok(kp)
79 }
80
81 pub fn identity(&self) -> &IdentityKeyPair {
83 self.proteus_identity.as_ref()
84 }
85
86 pub fn fingerprint(&self) -> String {
88 self.proteus_identity.as_ref().public_key.fingerprint()
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use core_crypto_keystore::DatabaseKey;
95
96 use super::*;
97 use crate::test_utils::*;
98
99 #[macro_rules_attribute::apply(smol_macros::test)]
100 async fn can_init() {
101 #[cfg(not(target_os = "unknown"))]
102 let (path, db_file) = tmp_db_file();
103 #[cfg(target_os = "unknown")]
104 let (path, _) = tmp_db_file();
105 let key = DatabaseKey::generate();
106 let keystore = core_crypto_keystore::Database::open(&path, &key).await.unwrap();
107 let tx = keystore.new_transaction().await.unwrap();
108 let central = ProteusCentral::try_new(&tx).await.unwrap();
109 let identity = (*central.proteus_identity).clone();
110 tx.commit().await.unwrap();
111
112 let keystore = core_crypto_keystore::Database::open(&path, &key).await.unwrap();
113 let tx = keystore.new_transaction().await.unwrap();
114 let central = ProteusCentral::try_new(&tx).await.unwrap();
115 tx.commit().await.unwrap();
116 assert_eq!(identity, *central.proteus_identity);
117
118 #[cfg(not(target_os = "unknown"))]
119 drop(db_file);
120 }
121}