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);
54 };
55
56 let sk = identity
57 .sk_raw()
58 .map_err(KeystoreError::wrap("reading the stored proteus identity secret key"))?;
59 let pk = identity
60 .pk_raw()
61 .map_err(KeystoreError::wrap("reading the stored proteus identity public key"))?;
62
63 IdentityKeyPair::from_raw_key_pair(*sk, *pk)
64 .map_err(ProteusError::wrap("constructing identity keypair"))
65 .map_err(Into::into)
66 }
67
68 fn create_identity(transaction: &Transaction) -> Result<IdentityKeyPair> {
70 let kp = IdentityKeyPair::new();
71 let pk = kp.public_key.public_key.as_slice().to_vec();
72
73 let ks_identity = ProteusIdentity {
74 sk: kp.secret_key.to_keypair_bytes().into(),
75 pk,
76 };
77 ks_identity
78 .save(transaction)
79 .map_err(KeystoreError::wrap("saving new proteus identity"))?;
80
81 Ok(kp)
82 }
83
84 pub fn identity(&self) -> &IdentityKeyPair {
86 self.proteus_identity.as_ref()
87 }
88
89 pub fn fingerprint(&self) -> String {
91 self.proteus_identity.as_ref().public_key.fingerprint()
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use core_crypto_keystore::DatabaseKey;
98
99 use super::*;
100 use crate::test_utils::*;
101
102 #[macro_rules_attribute::apply(smol_macros::test)]
103 async fn can_init() {
104 #[cfg(not(target_os = "unknown"))]
105 let (path, db_file) = tmp_db_file();
106 #[cfg(target_os = "unknown")]
107 let (path, _) = tmp_db_file();
108 let key = DatabaseKey::generate();
109 let keystore = core_crypto_keystore::Database::open(&path, &key).await.unwrap();
110 let tx = keystore.new_transaction().await.unwrap();
111 let central = ProteusCentral::try_new(&tx).await.unwrap();
112 let identity = (*central.proteus_identity).clone();
113 tx.commit().await.unwrap();
114
115 let keystore = core_crypto_keystore::Database::open(&path, &key).await.unwrap();
116 let tx = keystore.new_transaction().await.unwrap();
117 let central = ProteusCentral::try_new(&tx).await.unwrap();
118 tx.commit().await.unwrap();
119 assert_eq!(identity, *central.proteus_identity);
120
121 #[cfg(not(target_os = "unknown"))]
122 drop(db_file);
123 }
124}