Skip to content

Commit db585dc

Browse files
committed
feat(ffi): add support for starting and responding to user verification requests
1 parent d5d9898 commit db585dc

File tree

3 files changed

+127
-64
lines changed

3 files changed

+127
-64
lines changed

bindings/matrix-sdk-ffi/src/client.rs

+32-9
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@ use matrix_sdk::{
3232
user_directory::search_users,
3333
},
3434
events::{
35-
room::{avatar::RoomAvatarEventContent, encryption::RoomEncryptionEventContent},
36-
AnyInitialStateEvent, AnyToDeviceEvent, InitialStateEvent,
35+
room::{
36+
avatar::RoomAvatarEventContent, encryption::RoomEncryptionEventContent,
37+
message::MessageType,
38+
},
39+
AnyInitialStateEvent, InitialStateEvent,
3740
},
3841
serde::Raw,
3942
EventEncryptionAlgorithm, RoomId, TransactionId, UInt, UserId,
@@ -53,10 +56,12 @@ use ruma::{
5356
},
5457
events::{
5558
ignored_user_list::IgnoredUserListEventContent,
59+
key::verification::request::ToDeviceKeyVerificationRequestEvent,
5660
room::{
5761
join_rules::{
5862
AllowRule as RumaAllowRule, JoinRule as RumaJoinRule, RoomJoinRulesEventContent,
5963
},
64+
message::OriginalSyncRoomMessageEvent,
6065
power_levels::RoomPowerLevelsEventContent,
6166
},
6267
GlobalAccountDataEventType,
@@ -204,12 +209,27 @@ impl Client {
204209
tokio::sync::RwLock<Option<SessionVerificationController>>,
205210
> = Default::default();
206211
let controller = session_verification_controller.clone();
212+
sdk_client.add_event_handler(
213+
move |event: ToDeviceKeyVerificationRequestEvent| async move {
214+
if let Some(session_verification_controller) = &*controller.clone().read().await {
215+
session_verification_controller
216+
.process_incoming_verification_request(
217+
&event.sender,
218+
event.content.transaction_id,
219+
)
220+
.await;
221+
}
222+
},
223+
);
207224

208-
sdk_client.add_event_handler(move |ev: AnyToDeviceEvent| async move {
209-
if let Some(session_verification_controller) = &*controller.clone().read().await {
210-
session_verification_controller.process_to_device_message(ev).await;
211-
} else {
212-
debug!("received to-device message, but verification controller isn't ready");
225+
let controller = session_verification_controller.clone();
226+
sdk_client.add_event_handler(move |event: OriginalSyncRoomMessageEvent| async move {
227+
if let MessageType::VerificationRequest(_) = &event.content.msgtype {
228+
if let Some(session_verification_controller) = &*controller.clone().read().await {
229+
session_verification_controller
230+
.process_incoming_verification_request(&event.sender, event.event_id)
231+
.await;
232+
}
213233
}
214234
});
215235

@@ -777,8 +797,11 @@ impl Client {
777797
.await?
778798
.context("Failed retrieving user identity")?;
779799

780-
let session_verification_controller =
781-
SessionVerificationController::new(self.inner.encryption(), user_identity);
800+
let session_verification_controller = SessionVerificationController::new(
801+
self.inner.encryption(),
802+
user_identity,
803+
self.inner.account(),
804+
);
782805

783806
*self.session_verification_controller.write().await =
784807
Some(session_verification_controller.clone());

bindings/matrix-sdk-ffi/src/room.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,13 @@ impl Room {
252252
}
253253

254254
pub async fn member(&self, user_id: String) -> Result<RoomMember, ClientError> {
255-
let user_id = UserId::parse(&*user_id).context("Invalid user id.")?;
255+
let user_id = UserId::parse(&*user_id)?;
256256
let member = self.inner.get_member(&user_id).await?.context("User not found")?;
257257
Ok(member.try_into().context("Unknown state membership")?)
258258
}
259259

260260
pub async fn member_avatar_url(&self, user_id: String) -> Result<Option<String>, ClientError> {
261-
let user_id = UserId::parse(&*user_id).context("Invalid user id.")?;
261+
let user_id = UserId::parse(&*user_id)?;
262262
let member = self.inner.get_member(&user_id).await?.context("User not found")?;
263263
let avatar_url_string = member.avatar_url().map(|m| m.to_string());
264264
Ok(avatar_url_string)
@@ -268,7 +268,7 @@ impl Room {
268268
&self,
269269
user_id: String,
270270
) -> Result<Option<String>, ClientError> {
271-
let user_id = UserId::parse(&*user_id).context("Invalid user id.")?;
271+
let user_id = UserId::parse(&*user_id)?;
272272
let member = self.inner.get_member(&user_id).await?.context("User not found")?;
273273
let avatar_url_string = member.display_name().map(|m| m.to_owned());
274274
Ok(avatar_url_string)

bindings/matrix-sdk-ffi/src/session_verification.rs

+92-52
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use matrix_sdk::{
77
verification::{SasState, SasVerification, VerificationRequest, VerificationRequestState},
88
Encryption,
99
},
10-
ruma::events::{key::verification::VerificationMethod, AnyToDeviceEvent},
10+
ruma::events::key::verification::VerificationMethod,
11+
Account,
1112
};
1213
use ruma::UserId;
13-
use tracing::{error, info};
14+
use tracing::error;
1415

1516
use super::RUNTIME;
1617
use crate::{error::ClientError, utils::Timestamp};
@@ -42,9 +43,10 @@ pub enum SessionVerificationData {
4243
#[derive(Debug, uniffi::Record)]
4344
pub struct SessionVerificationRequestDetails {
4445
sender_id: String,
46+
sender_display_name: Option<String>,
4547
flow_id: String,
4648
device_id: String,
47-
display_name: Option<String>,
49+
device_display_name: Option<String>,
4850
/// First time this device was seen in milliseconds since epoch.
4951
first_seen_timestamp: Timestamp,
5052
}
@@ -66,6 +68,7 @@ pub type Delegate = Arc<RwLock<Option<Box<dyn SessionVerificationControllerDeleg
6668
pub struct SessionVerificationController {
6769
encryption: Encryption,
6870
user_identity: UserIdentity,
71+
account: Account,
6972
delegate: Delegate,
7073
verification_request: Arc<RwLock<Option<VerificationRequest>>>,
7174
sas_verification: Arc<RwLock<Option<SasVerification>>>,
@@ -94,15 +97,7 @@ impl SessionVerificationController {
9497
.await
9598
.ok_or(ClientError::new("Unknown session verification request"))?;
9699

97-
*self.verification_request.write().unwrap() = Some(verification_request.clone());
98-
99-
RUNTIME.spawn(Self::listen_to_verification_request_changes(
100-
verification_request,
101-
self.sas_verification.clone(),
102-
self.delegate.clone(),
103-
));
104-
105-
Ok(())
100+
self.set_ongoing_verification_request(verification_request)
106101
}
107102

108103
/// Accept the previously acknowledged verification request
@@ -118,23 +113,39 @@ impl SessionVerificationController {
118113
}
119114

120115
/// Request verification for the current device
121-
pub async fn request_verification(&self) -> Result<(), ClientError> {
116+
pub async fn request_device_verification(&self) -> Result<(), ClientError> {
122117
let methods = vec![VerificationMethod::SasV1];
123118
let verification_request = self
124119
.user_identity
125120
.request_verification_with_methods(methods)
126121
.await
127122
.map_err(anyhow::Error::from)?;
128123

129-
*self.verification_request.write().unwrap() = Some(verification_request.clone());
124+
self.set_ongoing_verification_request(verification_request)
125+
}
130126

131-
RUNTIME.spawn(Self::listen_to_verification_request_changes(
132-
verification_request,
133-
self.sas_verification.clone(),
134-
self.delegate.clone(),
135-
));
127+
/// Request verification for the given user
128+
pub async fn request_user_verification(&self, user_id: String) -> Result<(), ClientError> {
129+
let user_id = UserId::parse(user_id)?;
136130

137-
Ok(())
131+
let user_identity = self
132+
.encryption
133+
.get_user_identity(&user_id)
134+
.await?
135+
.ok_or(ClientError::new("Unknown user identity"))?;
136+
137+
if user_identity.is_verified() {
138+
return Err(ClientError::new("User is already verified"));
139+
}
140+
141+
let methods = vec![VerificationMethod::SasV1];
142+
143+
let verification_request = user_identity
144+
.request_verification_with_methods(methods)
145+
.await
146+
.map_err(anyhow::Error::from)?;
147+
148+
self.set_ongoing_verification_request(verification_request)
138149
}
139150

140151
/// Transition the current verification request into a SAS verification
@@ -202,50 +213,79 @@ impl SessionVerificationController {
202213
}
203214

204215
impl SessionVerificationController {
205-
pub(crate) fn new(encryption: Encryption, user_identity: UserIdentity) -> Self {
216+
pub(crate) fn new(
217+
encryption: Encryption,
218+
user_identity: UserIdentity,
219+
account: Account,
220+
) -> Self {
206221
SessionVerificationController {
207222
encryption,
208223
user_identity,
224+
account,
209225
delegate: Arc::new(RwLock::new(None)),
210226
verification_request: Arc::new(RwLock::new(None)),
211227
sas_verification: Arc::new(RwLock::new(None)),
212228
}
213229
}
214230

215-
pub(crate) async fn process_to_device_message(&self, event: AnyToDeviceEvent) {
216-
if let AnyToDeviceEvent::KeyVerificationRequest(event) = event {
217-
info!("Received verification request: {:}", event.sender);
218-
219-
let Some(request) = self
220-
.encryption
221-
.get_verification_request(&event.sender, &event.content.transaction_id)
222-
.await
223-
else {
224-
error!("Failed retrieving verification request");
225-
return;
226-
};
227-
228-
if !request.is_self_verification() {
229-
info!("Received non-self verification request. Ignoring.");
230-
return;
231-
}
231+
/// Ask the controller to process an incoming request based on the sender
232+
/// and flow identifier. It will fetch the request, verify that it's in the
233+
/// correct state and then and notify the delegate.
234+
pub(crate) async fn process_incoming_verification_request(
235+
&self,
236+
sender: &UserId,
237+
flow_id: impl AsRef<str>,
238+
) {
239+
let Some(request) = self.encryption.get_verification_request(sender, flow_id).await else {
240+
error!("Failed retrieving verification request");
241+
return;
242+
};
243+
244+
let VerificationRequestState::Requested { other_device_data, .. } = request.state() else {
245+
error!("Received verification request event but the request is in the wrong state.");
246+
return;
247+
};
232248

233-
let VerificationRequestState::Requested { other_device_data, .. } = request.state()
234-
else {
235-
error!("Received key verification event but the request is in the wrong state.");
236-
return;
237-
};
238-
239-
if let Some(delegate) = &*self.delegate.read().unwrap() {
240-
delegate.did_receive_verification_request(SessionVerificationRequestDetails {
241-
sender_id: request.other_user_id().into(),
242-
flow_id: request.flow_id().into(),
243-
device_id: other_device_data.device_id().into(),
244-
display_name: other_device_data.display_name().map(str::to_string),
245-
first_seen_timestamp: other_device_data.first_time_seen_ts().into(),
246-
});
249+
let Ok(user_profile) = self.account.fetch_user_profile_of(sender).await else {
250+
error!("Failed fetching user profile for verification request");
251+
return;
252+
};
253+
254+
if let Some(delegate) = &*self.delegate.read().unwrap() {
255+
delegate.did_receive_verification_request(SessionVerificationRequestDetails {
256+
sender_id: request.other_user_id().into(),
257+
sender_display_name: user_profile.displayname,
258+
flow_id: request.flow_id().into(),
259+
device_id: other_device_data.device_id().into(),
260+
device_display_name: other_device_data.display_name().map(str::to_string),
261+
first_seen_timestamp: other_device_data.first_time_seen_ts().into(),
262+
});
263+
}
264+
}
265+
266+
fn set_ongoing_verification_request(
267+
&self,
268+
verification_request: VerificationRequest,
269+
) -> Result<(), ClientError> {
270+
if let Some(ongoing_verification_request) =
271+
self.verification_request.read().unwrap().clone()
272+
{
273+
if !ongoing_verification_request.is_done()
274+
&& !ongoing_verification_request.is_cancelled()
275+
{
276+
return Err(ClientError::new("There is another verification flow ongoing."));
247277
}
248278
}
279+
280+
*self.verification_request.write().unwrap() = Some(verification_request.clone());
281+
282+
RUNTIME.spawn(Self::listen_to_verification_request_changes(
283+
verification_request,
284+
self.sas_verification.clone(),
285+
self.delegate.clone(),
286+
));
287+
288+
Ok(())
249289
}
250290

251291
async fn listen_to_verification_request_changes(

0 commit comments

Comments
 (0)