1use std::sync::{Arc, RwLock};
2
3use futures_util::StreamExt;
4use matrix_sdk::{
5 encryption::{
6 identities::UserIdentity,
7 verification::{SasState, SasVerification, VerificationRequest, VerificationRequestState},
8 Encryption,
9 },
10 ruma::events::key::verification::VerificationMethod,
11 Account,
12};
13use ruma::UserId;
14use tracing::{error, warn};
15
16use super::RUNTIME;
17use crate::{client::UserProfile, error::ClientError, utils::Timestamp};
18
19#[derive(uniffi::Object)]
20pub struct SessionVerificationEmoji {
21 symbol: String,
22 description: String,
23}
24
25#[matrix_sdk_ffi_macros::export]
26impl SessionVerificationEmoji {
27 pub fn symbol(&self) -> String {
28 self.symbol.clone()
29 }
30
31 pub fn description(&self) -> String {
32 self.description.clone()
33 }
34}
35
36#[derive(uniffi::Enum)]
37pub enum SessionVerificationData {
38 Emojis { emojis: Vec<Arc<SessionVerificationEmoji>>, indices: Vec<u8> },
39 Decimals { values: Vec<u16> },
40}
41
42#[derive(uniffi::Record)]
44pub struct SessionVerificationRequestDetails {
45 sender_profile: UserProfile,
46 flow_id: String,
47 device_id: String,
48 device_display_name: Option<String>,
49 first_seen_timestamp: Timestamp,
51}
52
53#[matrix_sdk_ffi_macros::export(callback_interface)]
54pub trait SessionVerificationControllerDelegate: Sync + Send {
55 fn did_receive_verification_request(&self, details: SessionVerificationRequestDetails);
56 fn did_accept_verification_request(&self);
57 fn did_start_sas_verification(&self);
58 fn did_receive_verification_data(&self, data: SessionVerificationData);
59 fn did_fail(&self);
60 fn did_cancel(&self);
61 fn did_finish(&self);
62}
63
64pub type Delegate = Arc<RwLock<Option<Box<dyn SessionVerificationControllerDelegate>>>>;
65
66#[derive(Clone, uniffi::Object)]
67pub struct SessionVerificationController {
68 encryption: Encryption,
69 user_identity: UserIdentity,
70 account: Account,
71 delegate: Delegate,
72 verification_request: Arc<RwLock<Option<VerificationRequest>>>,
73 sas_verification: Arc<RwLock<Option<SasVerification>>>,
74}
75
76#[matrix_sdk_ffi_macros::export]
77impl SessionVerificationController {
78 pub fn set_delegate(&self, delegate: Option<Box<dyn SessionVerificationControllerDelegate>>) {
79 *self.delegate.write().unwrap() = delegate;
80 }
81
82 pub async fn acknowledge_verification_request(
87 &self,
88 sender_id: String,
89 flow_id: String,
90 ) -> Result<(), ClientError> {
91 let sender_id = UserId::parse(sender_id.clone())?;
92
93 let verification_request = self
94 .encryption
95 .get_verification_request(&sender_id, flow_id)
96 .await
97 .ok_or(ClientError::new("Unknown session verification request"))?;
98
99 self.set_ongoing_verification_request(verification_request)
100 }
101
102 pub async fn accept_verification_request(&self) -> Result<(), ClientError> {
104 let verification_request = self.verification_request.read().unwrap().clone();
105
106 if let Some(verification_request) = verification_request {
107 let methods = vec![VerificationMethod::SasV1];
108 verification_request.accept_with_methods(methods).await?;
109 }
110
111 Ok(())
112 }
113
114 pub async fn request_device_verification(&self) -> Result<(), ClientError> {
116 let methods = vec![VerificationMethod::SasV1];
117 let verification_request = self
118 .user_identity
119 .request_verification_with_methods(methods)
120 .await
121 .map_err(anyhow::Error::from)?;
122
123 self.set_ongoing_verification_request(verification_request)
124 }
125
126 pub async fn request_user_verification(&self, user_id: String) -> Result<(), ClientError> {
128 let user_id = UserId::parse(user_id)?;
129
130 let user_identity = self
131 .encryption
132 .get_user_identity(&user_id)
133 .await?
134 .ok_or(ClientError::new("Unknown user identity"))?;
135
136 if user_identity.is_verified() {
137 return Err(ClientError::new("User is already verified"));
138 }
139
140 let methods = vec![VerificationMethod::SasV1];
141
142 let verification_request = user_identity
143 .request_verification_with_methods(methods)
144 .await
145 .map_err(anyhow::Error::from)?;
146
147 self.set_ongoing_verification_request(verification_request)
148 }
149
150 pub async fn start_sas_verification(&self) -> Result<(), ClientError> {
153 let verification_request = self.verification_request.read().unwrap().clone();
154
155 let Some(verification_request) = verification_request else {
156 return Err(ClientError::new("Verification request missing."));
157 };
158
159 match verification_request.start_sas().await {
160 Ok(Some(verification)) => {
161 *self.sas_verification.write().unwrap() = Some(verification.clone());
162
163 if let Some(delegate) = &*self.delegate.read().unwrap() {
164 delegate.did_start_sas_verification()
165 }
166
167 let delegate = self.delegate.clone();
168 RUNTIME.spawn(Self::listen_to_sas_verification_changes(verification, delegate));
169 }
170 _ => {
171 if let Some(delegate) = &*self.delegate.read().unwrap() {
172 delegate.did_fail()
173 }
174 }
175 }
176
177 Ok(())
178 }
179
180 pub async fn approve_verification(&self) -> Result<(), ClientError> {
182 let sas_verification = self.sas_verification.read().unwrap().clone();
183
184 let Some(sas_verification) = sas_verification else {
185 return Err(ClientError::new("SAS verification missing"));
186 };
187
188 Ok(sas_verification.confirm().await?)
189 }
190
191 pub async fn decline_verification(&self) -> Result<(), ClientError> {
193 let sas_verification = self.sas_verification.read().unwrap().clone();
194
195 let Some(sas_verification) = sas_verification else {
196 return Err(ClientError::new("SAS verification missing"));
197 };
198
199 Ok(sas_verification.mismatch().await?)
200 }
201
202 pub async fn cancel_verification(&self) -> Result<(), ClientError> {
204 let verification_request = self.verification_request.read().unwrap().clone();
205
206 let Some(verification_request) = verification_request else {
207 return Err(ClientError::new("Verification request missing."));
208 };
209
210 Ok(verification_request.cancel().await?)
211 }
212}
213
214impl SessionVerificationController {
215 pub(crate) fn new(
216 encryption: Encryption,
217 user_identity: UserIdentity,
218 account: Account,
219 ) -> Self {
220 SessionVerificationController {
221 encryption,
222 user_identity,
223 account,
224 delegate: Arc::new(RwLock::new(None)),
225 verification_request: Arc::new(RwLock::new(None)),
226 sas_verification: Arc::new(RwLock::new(None)),
227 }
228 }
229
230 pub(crate) async fn process_incoming_verification_request(
234 &self,
235 sender: &UserId,
236 flow_id: impl AsRef<str>,
237 ) {
238 if sender != self.user_identity.user_id() {
239 if let Some(status) = self.encryption.cross_signing_status().await {
240 if !status.is_complete() {
241 warn!("Cannot verify other users until our own device's cross-signing status is complete: {:?}", status);
242 return;
243 }
244 }
245 }
246
247 let Some(request) = self.encryption.get_verification_request(sender, flow_id).await else {
248 error!("Failed retrieving verification request");
249 return;
250 };
251
252 let VerificationRequestState::Requested { other_device_data, .. } = request.state() else {
253 error!("Received verification request event but the request is in the wrong state.");
254 return;
255 };
256
257 let Ok(sender_profile) = self.account.fetch_user_profile_of(sender).await else {
258 error!("Failed fetching user profile for verification request");
259 return;
260 };
261
262 if let Some(delegate) = &*self.delegate.read().unwrap() {
263 delegate.did_receive_verification_request(SessionVerificationRequestDetails {
264 sender_profile: UserProfile {
265 user_id: request.other_user_id().to_string(),
266 display_name: sender_profile.displayname,
267 avatar_url: sender_profile.avatar_url.as_ref().map(|url| url.to_string()),
268 },
269 flow_id: request.flow_id().into(),
270 device_id: other_device_data.device_id().into(),
271 device_display_name: other_device_data.display_name().map(str::to_string),
272 first_seen_timestamp: other_device_data.first_time_seen_ts().into(),
273 });
274 }
275 }
276
277 fn set_ongoing_verification_request(
278 &self,
279 verification_request: VerificationRequest,
280 ) -> Result<(), ClientError> {
281 if let Some(ongoing_verification_request) =
282 self.verification_request.read().unwrap().clone()
283 {
284 if !ongoing_verification_request.is_done()
285 && !ongoing_verification_request.is_cancelled()
286 {
287 return Err(ClientError::new("There is another verification flow ongoing."));
288 }
289 }
290
291 *self.verification_request.write().unwrap() = Some(verification_request.clone());
292
293 RUNTIME.spawn(Self::listen_to_verification_request_changes(
294 verification_request,
295 self.sas_verification.clone(),
296 self.delegate.clone(),
297 ));
298
299 Ok(())
300 }
301
302 async fn listen_to_verification_request_changes(
303 verification_request: VerificationRequest,
304 sas_verification: Arc<RwLock<Option<SasVerification>>>,
305 delegate: Delegate,
306 ) {
307 let mut stream = verification_request.changes();
308
309 while let Some(state) = stream.next().await {
310 match state {
311 VerificationRequestState::Transitioned { verification } => {
312 let Some(verification) = verification.sas() else {
313 error!("Invalid, non-sas verification flow. Returning.");
314 return;
315 };
316
317 *sas_verification.write().unwrap() = Some(verification.clone());
318
319 if verification.accept().await.is_ok() {
320 if let Some(delegate) = &*delegate.read().unwrap() {
321 delegate.did_start_sas_verification()
322 }
323
324 let delegate = delegate.clone();
325 RUNTIME.spawn(Self::listen_to_sas_verification_changes(
326 verification,
327 delegate,
328 ));
329 } else if let Some(delegate) = &*delegate.read().unwrap() {
330 delegate.did_fail()
331 }
332 }
333 VerificationRequestState::Ready { .. } => {
334 if let Some(delegate) = &*delegate.read().unwrap() {
335 delegate.did_accept_verification_request()
336 }
337 }
338 VerificationRequestState::Cancelled(..) => {
339 if let Some(delegate) = &*delegate.read().unwrap() {
340 delegate.did_cancel();
341 }
342 }
343 _ => {}
344 }
345 }
346 }
347
348 async fn listen_to_sas_verification_changes(sas: SasVerification, delegate: Delegate) {
349 let mut stream = sas.changes();
350
351 while let Some(state) = stream.next().await {
352 match state {
353 SasState::KeysExchanged { emojis, decimals } => {
354 if let Some(delegate) = &*delegate.read().unwrap() {
355 if let Some(emojis) = emojis {
356 delegate.did_receive_verification_data(
357 SessionVerificationData::Emojis {
358 emojis: emojis
359 .emojis
360 .into_iter()
361 .map(|emoji| {
362 Arc::new(SessionVerificationEmoji {
363 symbol: emoji.symbol.to_owned(),
364 description: emoji.description.to_owned(),
365 })
366 })
367 .collect(),
368 indices: emojis.indices.to_vec(),
369 },
370 );
371 } else {
372 delegate.did_receive_verification_data(
373 SessionVerificationData::Decimals {
374 values: vec![decimals.0, decimals.1, decimals.2],
375 },
376 )
377 }
378 }
379 }
380 SasState::Done { .. } => {
381 if let Some(delegate) = &*delegate.read().unwrap() {
382 delegate.did_finish()
383 }
384 break;
385 }
386 SasState::Cancelled(_cancel_info) => {
387 if let Some(delegate) = &*delegate.read().unwrap() {
390 delegate.did_cancel()
391 }
392 break;
393 }
394 SasState::Created { .. }
395 | SasState::Started { .. }
396 | SasState::Accepted { .. }
397 | SasState::Confirmed => (),
398 }
399 }
400 }
401}