Skip to main content

core_crypto/transaction_context/
proteus.rs

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