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