interop/clients/corecrypto/
ffi.rs1use color_eyre::eyre::Result;
18use core_crypto_ffi::{
19 context::TransactionHelper, ClientId, CoreCrypto, CustomConfiguration, MlsCredentialType, UniffiCustomTypeConverter,
20};
21use std::sync::Arc;
22
23use crate::{
24 clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedMlsClient},
25 CIPHERSUITE_IN_USE,
26};
27
28#[derive(Debug)]
29pub(crate) struct CoreCryptoFfiClient {
30 cc: CoreCrypto,
31 client_id: Vec<u8>,
32 #[cfg(feature = "proteus")]
33 prekey_last_id: u16,
34}
35
36impl CoreCryptoFfiClient {
37 pub(crate) async fn new() -> Result<CoreCryptoFfiClient> {
38 let client_id = uuid::Uuid::new_v4();
39 let client_id_bytes: Vec<u8> = client_id.as_hyphenated().to_string().as_bytes().into();
40 let client_id = ClientId::into_custom(client_id_bytes.clone()).unwrap();
41 let ciphersuite = CIPHERSUITE_IN_USE;
42 let cc = CoreCrypto::new(
43 "path".into(),
44 "key".into(),
45 Some(client_id),
46 Some(vec![ciphersuite].into()),
47 None,
48 )
49 .await?;
50 Ok(Self {
51 cc,
52 client_id: client_id_bytes,
53 #[cfg(feature = "proteus")]
54 prekey_last_id: 0,
55 })
56 }
57}
58
59#[async_trait::async_trait(?Send)]
60impl EmulatedClient for CoreCryptoFfiClient {
61 fn client_name(&self) -> &str {
62 "CoreCrypto::ffi"
63 }
64
65 fn client_type(&self) -> EmulatedClientType {
66 EmulatedClientType::Native
67 }
68
69 fn client_id(&self) -> &[u8] {
70 self.client_id.as_slice()
71 }
72
73 fn client_protocol(&self) -> EmulatedClientProtocol {
74 EmulatedClientProtocol::MLS | EmulatedClientProtocol::PROTEUS
75 }
76
77 async fn wipe(mut self) -> Result<()> {
78 Ok(Arc::new(self.cc).wipe().await?)
79 }
80}
81
82#[async_trait::async_trait(?Send)]
83impl EmulatedMlsClient for CoreCryptoFfiClient {
84 async fn get_keypackage(&mut self) -> Result<Vec<u8>> {
85 let ciphersuite = CIPHERSUITE_IN_USE.into();
86 let credential_type = MlsCredentialType::Basic;
87 let extractor = TransactionHelper::new(move |context| async move {
88 Ok(context
89 .client_keypackages(ciphersuite, credential_type, 1)
90 .await?
91 .pop()
92 .unwrap())
93 });
94 self.cc.transaction(extractor.clone()).await?;
95 let kp = extractor.into_return_value();
96 Ok(kp)
97 }
98
99 async fn add_client(&mut self, conversation_id: &[u8], kp: &[u8]) -> Result<Vec<u8>> {
100 if !self.cc.conversation_exists(conversation_id.to_vec()).await? {
101 let cfg = core_crypto_ffi::ConversationConfiguration {
102 ciphersuite: CIPHERSUITE_IN_USE.into(),
103 external_senders: vec![],
104 custom: CustomConfiguration {
105 key_rotation_span: None,
106 wire_policy: None,
107 },
108 };
109 let conversation_id = conversation_id.to_vec();
110 self.cc
111 .transaction(TransactionHelper::new(move |context| async move {
112 context
113 .create_conversation(conversation_id, MlsCredentialType::Basic, cfg)
114 .await?;
115 Ok(())
116 }))
117 .await?;
118 }
119
120 let conversation_id = conversation_id.to_vec();
121 let key_packages = vec![kp.to_vec()];
122 let extractor = TransactionHelper::new(move |context| async move {
123 context.add_clients_to_conversation(conversation_id, key_packages).await
124 });
125 self.cc.transaction(extractor.clone()).await?;
126 let welcome = extractor.into_return_value();
127
128 Ok(welcome.welcome)
129 }
130
131 async fn kick_client(&mut self, conversation_id: &[u8], client_id: &[u8]) -> Result<Vec<u8>> {
132 let client_id = ClientId::into_custom(client_id.to_vec()).unwrap();
133 let conversation_id = conversation_id.to_vec();
134 let extractor = TransactionHelper::new(move |context| async move {
135 context
136 .remove_clients_from_conversation(conversation_id, vec![client_id])
137 .await
138 });
139 self.cc.transaction(extractor.clone()).await?;
140 let commit = extractor.into_return_value();
141
142 Ok(commit.commit)
143 }
144
145 async fn process_welcome(&mut self, welcome: &[u8]) -> Result<Vec<u8>> {
146 let cfg = CustomConfiguration {
147 key_rotation_span: None,
148 wire_policy: None,
149 };
150 let welcome = welcome.to_vec();
151 let extractor =
152 TransactionHelper::new(move |context| async move { context.process_welcome_message(welcome, cfg).await });
153 self.cc.transaction(extractor.clone()).await?;
154 Ok(extractor.into_return_value().id)
155 }
156
157 async fn encrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Vec<u8>> {
158 let conversation_id = conversation_id.to_vec();
159 let message = message.to_vec();
160 let extractor =
161 TransactionHelper::new(
162 move |context| async move { context.encrypt_message(conversation_id, message).await },
163 );
164 self.cc.transaction(extractor.clone()).await?;
165 Ok(extractor.into_return_value())
166 }
167
168 async fn decrypt_message(&mut self, conversation_id: &[u8], message: &[u8]) -> Result<Option<Vec<u8>>> {
169 let conversation_id = conversation_id.to_vec();
170 let message = message.to_vec();
171 let extractor =
172 TransactionHelper::new(
173 move |context| async move { context.decrypt_message(conversation_id, message).await },
174 );
175 self.cc.transaction(extractor.clone()).await?;
176 Ok(extractor.into_return_value().message)
177 }
178}
179
180#[cfg(feature = "proteus")]
181#[async_trait::async_trait(?Send)]
182impl crate::clients::EmulatedProteusClient for CoreCryptoFfiClient {
183 async fn init(&mut self) -> Result<()> {
184 self.cc
185 .transaction(TransactionHelper::new(move |context| async move {
186 context.proteus_init().await
187 }))
188 .await?;
189 Ok(())
190 }
191
192 async fn get_prekey(&mut self) -> Result<Vec<u8>> {
193 self.prekey_last_id += 1;
194 let prekey_last_id = self.prekey_last_id;
195 let extractor =
196 TransactionHelper::new(move |context| async move { context.proteus_new_prekey(prekey_last_id).await });
197 self.cc.transaction(extractor.clone()).await?;
198 Ok(extractor.into_return_value())
199 }
200
201 async fn session_from_prekey(&mut self, session_id: &str, prekey: &[u8]) -> Result<()> {
202 let session_id = session_id.to_string();
203 let prekey = prekey.to_vec();
204 self.cc
205 .transaction(TransactionHelper::new(move |context| async move {
206 context.proteus_session_from_prekey(session_id, prekey).await
207 }))
208 .await?;
209 Ok(())
210 }
211
212 async fn session_from_message(&mut self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
213 let session_id = session_id.to_string();
214 let message = message.to_vec();
215 let extractor = TransactionHelper::new(move |context| async move {
216 context.proteus_session_from_message(session_id, message).await
217 });
218 self.cc.transaction(extractor.clone()).await?;
219 Ok(extractor.into_return_value())
220 }
221
222 async fn encrypt(&mut self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
223 let session_id = session_id.to_string();
224 let plaintext = plaintext.to_vec();
225 let extractor =
226 TransactionHelper::new(move |context| async move { context.proteus_encrypt(session_id, plaintext).await });
227 self.cc.transaction(extractor.clone()).await?;
228 Ok(extractor.into_return_value())
229 }
230
231 async fn decrypt(&mut self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
232 let session_id = session_id.to_string();
233 let ciphertext = ciphertext.to_vec();
234 let extractor =
235 TransactionHelper::new(move |context| async move { context.proteus_decrypt(session_id, ciphertext).await });
236 self.cc.transaction(extractor.clone()).await?;
237 Ok(extractor.into_return_value())
238 }
239
240 async fn fingerprint(&self) -> Result<String> {
241 self.cc.proteus_fingerprint().await.map_err(Into::into)
242 }
243}