core_crypto/transaction_context/
proteus.rs

1//! This module contains all [super::TransactionContext] methods concerning proteus.
2
3use crate::{
4    RecursiveError,
5    group_store::GroupStoreValue,
6    proteus::{ProteusCentral, ProteusConversationSession},
7};
8
9use super::{Error, Result, TransactionContext};
10
11impl TransactionContext {
12    /// Initializes the proteus client
13    pub async fn proteus_init(&self) -> Result<()> {
14        let keystore = self.keystore().await?;
15        let proteus_client = ProteusCentral::try_new(&keystore)
16            .await
17            .map_err(RecursiveError::root("creating new proteus client"))?;
18
19        // ? Make sure the last resort prekey exists
20        let _ = proteus_client
21            .last_resort_prekey(&keystore)
22            .await
23            .map_err(RecursiveError::root("getting last resort prekey"))?;
24
25        let mutex = self.proteus_central().await?;
26        let mut guard = mutex.lock().await;
27        *guard = Some(proteus_client);
28        Ok(())
29    }
30
31    /// Reloads the sessions from the key store
32    ///
33    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or it will do nothing
34    pub async fn proteus_reload_sessions(&self) -> Result<()> {
35        let arc = self.proteus_central().await?;
36        let mut mutex = arc.lock().await;
37        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
38        let keystore = self.keystore().await?;
39        proteus
40            .reload_sessions(&keystore)
41            .await
42            .map_err(RecursiveError::root("reloading proteus session"))
43            .map_err(Into::into)
44    }
45
46    /// Creates a proteus session from a prekey
47    ///
48    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
49    pub async fn proteus_session_from_prekey(
50        &self,
51        session_id: &str,
52        prekey: &[u8],
53    ) -> Result<GroupStoreValue<ProteusConversationSession>> {
54        let arc = self.proteus_central().await?;
55        let mut mutex = arc.lock().await;
56        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
57        let keystore = self.keystore().await?;
58        let session = proteus
59            .session_from_prekey(session_id, prekey)
60            .await
61            .map_err(RecursiveError::root("creating proteus session from prekey"))?;
62        ProteusCentral::session_save_by_ref(&keystore, session.clone())
63            .await
64            .map_err(RecursiveError::root("saving proteus session by ref"))?;
65
66        Ok(session)
67    }
68
69    /// Creates a proteus session from a Proteus message envelope
70    ///
71    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
72    pub async fn proteus_session_from_message(
73        &self,
74        session_id: &str,
75        envelope: &[u8],
76    ) -> Result<(GroupStoreValue<ProteusConversationSession>, Vec<u8>)> {
77        let arc = self.proteus_central().await?;
78        let mut mutex = arc.lock().await;
79        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
80        let mut keystore = self.keystore().await?;
81        let (session, message) = proteus
82            .session_from_message(&mut keystore, session_id, envelope)
83            .await
84            .map_err(RecursiveError::root("creating proteus sesseion from message"))?;
85        ProteusCentral::session_save_by_ref(&keystore, session.clone())
86            .await
87            .map_err(RecursiveError::root("saving proteus session by ref"))?;
88
89        Ok((session, message))
90    }
91
92    /// Saves a proteus session in the keystore
93    ///
94    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
95    pub async fn proteus_session_save(&self, session_id: &str) -> Result<()> {
96        let arc = self.proteus_central().await?;
97        let mut mutex = arc.lock().await;
98        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
99        let keystore = self.keystore().await?;
100        proteus
101            .session_save(&keystore, session_id)
102            .await
103            .map_err(RecursiveError::root("saving proteus session"))
104            .map_err(Into::into)
105    }
106
107    /// Deletes a proteus session from the keystore
108    ///
109    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
110    pub async fn proteus_session_delete(&self, session_id: &str) -> Result<()> {
111        let arc = self.proteus_central().await?;
112        let mut mutex = arc.lock().await;
113        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
114        let keystore = self.keystore().await?;
115        proteus
116            .session_delete(&keystore, session_id)
117            .await
118            .map_err(RecursiveError::root("deleting proteus session"))
119            .map_err(Into::into)
120    }
121
122    /// Proteus session accessor
123    ///
124    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
125    pub async fn proteus_session(
126        &self,
127        session_id: &str,
128    ) -> Result<Option<GroupStoreValue<ProteusConversationSession>>> {
129        let arc = self.proteus_central().await?;
130        let mut mutex = arc.lock().await;
131        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
132        let keystore = self.keystore().await?;
133        proteus
134            .session(session_id, &keystore)
135            .await
136            .map_err(RecursiveError::root("getting proteus session"))
137            .map_err(Into::into)
138    }
139
140    /// Proteus session exists
141    ///
142    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
143    pub async fn proteus_session_exists(&self, session_id: &str) -> Result<bool> {
144        let arc = self.proteus_central().await?;
145        let mut mutex = arc.lock().await;
146        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
147        let keystore = self.keystore().await?;
148        Ok(proteus.session_exists(session_id, &keystore).await)
149    }
150
151    /// Decrypts a proteus message envelope
152    ///
153    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
154    pub async fn proteus_decrypt(&self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
155        let arc = self.proteus_central().await?;
156        let mut mutex = arc.lock().await;
157        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
158        let mut keystore = self.keystore().await?;
159        proteus
160            .decrypt(&mut keystore, session_id, ciphertext)
161            .await
162            .map_err(RecursiveError::root("decrypting proteus message"))
163            .map_err(Into::into)
164    }
165
166    /// Encrypts proteus message for a given session ID
167    ///
168    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
169    pub async fn proteus_encrypt(&self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
170        let arc = self.proteus_central().await?;
171        let mut mutex = arc.lock().await;
172        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
173        let mut keystore = self.keystore().await?;
174        proteus
175            .encrypt(&mut keystore, session_id, plaintext)
176            .await
177            .map_err(RecursiveError::root("encrypting proteus message"))
178            .map_err(Into::into)
179    }
180
181    /// Encrypts a proteus message for several sessions ID. This is more efficient than other methods as the calls are batched.
182    /// This also reduces the rountrips when crossing over the FFI
183    ///
184    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
185    pub async fn proteus_encrypt_batched(
186        &self,
187        sessions: &[impl AsRef<str>],
188        plaintext: &[u8],
189    ) -> Result<std::collections::HashMap<String, Vec<u8>>> {
190        let arc = self.proteus_central().await?;
191        let mut mutex = arc.lock().await;
192        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
193        let mut keystore = self.keystore().await?;
194        proteus
195            .encrypt_batched(&mut keystore, sessions, plaintext)
196            .await
197            .map_err(RecursiveError::root("batch encrypting proteus message"))
198            .map_err(Into::into)
199    }
200
201    /// Creates a new Proteus prekey and returns the CBOR-serialized version of the prekey bundle
202    ///
203    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
204    pub async fn proteus_new_prekey(&self, prekey_id: u16) -> Result<Vec<u8>> {
205        let arc = self.proteus_central().await?;
206        let mut mutex = arc.lock().await;
207        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
208        let keystore = self.keystore().await?;
209        proteus
210            .new_prekey(prekey_id, &keystore)
211            .await
212            .map_err(RecursiveError::root("new proteus prekey"))
213            .map_err(Into::into)
214    }
215
216    /// Creates a new Proteus prekey with an automatically incremented ID and returns the CBOR-serialized version of the prekey bundle
217    ///
218    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
219    pub async fn proteus_new_prekey_auto(&self) -> Result<(u16, Vec<u8>)> {
220        let arc = self.proteus_central().await?;
221        let mut mutex = arc.lock().await;
222        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
223        let keystore = self.keystore().await?;
224        proteus
225            .new_prekey_auto(&keystore)
226            .await
227            .map_err(RecursiveError::root("proteus new prekey auto"))
228            .map_err(Into::into)
229    }
230
231    /// Returns the last resort prekey
232    pub async fn proteus_last_resort_prekey(&self) -> Result<Vec<u8>> {
233        let arc = self.proteus_central().await?;
234        let mut mutex = arc.lock().await;
235        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
236        let keystore = self.keystore().await?;
237
238        proteus
239            .last_resort_prekey(&keystore)
240            .await
241            .map_err(RecursiveError::root("getting proteus last resort prekey"))
242            .map_err(Into::into)
243    }
244
245    /// Returns the proteus last resort prekey id (u16::MAX = 65535)
246    pub fn proteus_last_resort_prekey_id() -> u16 {
247        ProteusCentral::last_resort_prekey_id()
248    }
249
250    /// Returns the proteus identity's public key fingerprint
251    ///
252    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
253    pub async fn proteus_fingerprint(&self) -> Result<String> {
254        let arc = self.proteus_central().await?;
255        let mut mutex = arc.lock().await;
256        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
257        Ok(proteus.fingerprint())
258    }
259
260    /// Returns the proteus identity's public key fingerprint
261    ///
262    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
263    pub async fn proteus_fingerprint_local(&self, session_id: &str) -> Result<String> {
264        let arc = self.proteus_central().await?;
265        let mut mutex = arc.lock().await;
266        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
267        let keystore = self.keystore().await?;
268        proteus
269            .fingerprint_local(session_id, &keystore)
270            .await
271            .map_err(RecursiveError::root("getting proteus fingerprint local"))
272            .map_err(Into::into)
273    }
274
275    /// Returns the proteus identity's public key fingerprint
276    ///
277    /// Warning: The Proteus client **MUST** be initialized with [TransactionContext::proteus_init] first or an error will be returned
278    pub async fn proteus_fingerprint_remote(&self, session_id: &str) -> Result<String> {
279        let arc = self.proteus_central().await?;
280        let mut mutex = arc.lock().await;
281        let proteus = mutex.as_mut().ok_or(Error::ProteusNotInitialized)?;
282        let keystore = self.keystore().await?;
283        proteus
284            .fingerprint_remote(session_id, &keystore)
285            .await
286            .map_err(RecursiveError::root("geeting proteus fingerprint remote"))
287            .map_err(Into::into)
288    }
289
290    /// Migrates an existing Cryptobox data store (whether a folder or an IndexedDB database) located at `path` to the keystore.
291    ///
292    ///The client can then be initialized with [TransactionContext::proteus_init]
293    pub async fn proteus_cryptobox_migrate(&self, path: &str) -> Result<()> {
294        let keystore = self.keystore().await?;
295        ProteusCentral::cryptobox_migrate(&keystore, path)
296            .await
297            .map_err(RecursiveError::root("migrating from cryptobox"))
298            .map_err(Into::into)
299    }
300}