From f497eebf009583db86f27af6b8782f8644d06a83 Mon Sep 17 00:00:00 2001 From: bitfriend Date: Sat, 7 Dec 2024 08:36:00 +0800 Subject: [PATCH 01/10] Wrap receiver in broadcast so that device_event_rx can be called multiple times --- .../providers/notifiers/devices_notifier.dart | 8 +++--- native/acter/api.rsh | 2 +- native/acter/src/api/device.rs | 25 ++++++++--------- .../rust_sdk/lib/acter_flutter_sdk_ffi.dart | 27 ++++++------------- 4 files changed, 26 insertions(+), 36 deletions(-) diff --git a/app/lib/features/settings/providers/notifiers/devices_notifier.dart b/app/lib/features/settings/providers/notifiers/devices_notifier.dart index 3d9698500d33..2676a1cd8ada 100644 --- a/app/lib/features/settings/providers/notifiers/devices_notifier.dart +++ b/app/lib/features/settings/providers/notifiers/devices_notifier.dart @@ -9,8 +9,8 @@ import 'package:riverpod/riverpod.dart'; final _log = Logger('a3::settings::devices_notifier'); class AsyncDevicesNotifier extends AsyncNotifier> { - Stream? _listener; - StreamSubscription? _poller; + late Stream _listener; + late StreamSubscription _poller; Future> _getSessions(SessionManager manager) async { return (await manager.allSessions()).toList(); @@ -22,7 +22,7 @@ class AsyncDevicesNotifier extends AsyncNotifier> { final manager = client.sessionManager(); _listener = client.deviceEventRx(); - _poller = _listener?.listen( + _poller = _listener.listen( (data) async { state = await AsyncValue.guard(() async => await _getSessions(manager)); }, @@ -33,7 +33,7 @@ class AsyncDevicesNotifier extends AsyncNotifier> { _log.info('stream ended'); }, ); - ref.onDispose(() => _poller?.cancel()); + ref.onDispose(() => _poller.cancel()); return await _getSessions(manager); } diff --git a/native/acter/api.rsh b/native/acter/api.rsh index b3f1edf93e82..bc84e833981b 100644 --- a/native/acter/api.rsh +++ b/native/acter/api.rsh @@ -2819,7 +2819,7 @@ object Client { fn install_sas_event_handler(flow_id: string) -> Future>; /// Return the event handler that new device was found or existing device was changed - fn device_event_rx() -> Option>; + fn device_event_rx() -> Stream; /// Return the typing event receiver fn subscribe_to_typing_event_stream(room_id: string) -> Stream; diff --git a/native/acter/src/api/device.rs b/native/acter/src/api/device.rs index 2c629e7de7e0..9c3c5c9d8577 100644 --- a/native/acter/src/api/device.rs +++ b/native/acter/src/api/device.rs @@ -1,8 +1,7 @@ use anyhow::{Context, Result}; use futures::{ - channel::mpsc::{channel, Receiver, Sender}, pin_mut, - stream::StreamExt, + stream::{Stream, StreamExt}, }; use matrix_sdk::{executor::JoinHandle, Client as SdkClient}; use matrix_sdk_base::ruma::{OwnedDeviceId, OwnedUserId}; @@ -10,12 +9,16 @@ use std::{ sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use tokio::sync::Mutex; +use tokio::sync::{ + broadcast::{channel, Receiver, Sender}, + Mutex, +}; +use tokio_stream::wrappers::BroadcastStream; use tracing::{error, info}; use super::{client::Client, common::DeviceRecord, RUNTIME}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct DeviceEvent { new_devices: Vec, changed_devices: Vec, @@ -50,7 +53,7 @@ impl DeviceEvent { #[derive(Clone, Debug)] pub(crate) struct DeviceController { event_tx: Sender, // keep it resident in memory - event_rx: Arc>>>, + event_rx: Arc>, listener: Arc>, // keep it resident in memory } @@ -89,7 +92,7 @@ impl DeviceController { } if !new_devices.is_empty() || !changed_devices.is_empty() { let evt = DeviceEvent::new(new_devices, changed_devices); - if let Err(e) = tx.try_send(evt) { + if let Err(e) = tx.send(evt) { error!("Dropping device event: {}", e); } } @@ -98,18 +101,16 @@ impl DeviceController { DeviceController { event_tx, - event_rx: Arc::new(Mutex::new(Some(event_rx))), + event_rx: Arc::new(event_rx), listener: Arc::new(listener), } } } impl Client { - pub fn device_event_rx(&self) -> Option> { - match self.device_controller.event_rx.try_lock() { - Ok(mut r) => r.take(), - Err(e) => None, - } + pub fn device_event_rx(&self) -> impl Stream { + BroadcastStream::new(self.device_controller.event_rx.resubscribe()) + .map(|o| o.unwrap_or_default()) } pub async fn device_records(&self, verified: bool) -> Result> { diff --git a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart index 38921509468c..f964c877d979 100644 --- a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart +++ b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart @@ -27051,12 +27051,12 @@ class Api { )>(); late final _clientDeviceEventRxPtr = _lookup< ffi.NativeFunction< - _ClientDeviceEventRxReturn Function( + ffi.IntPtr Function( ffi.IntPtr, )>>("__Client_device_event_rx"); late final _clientDeviceEventRx = _clientDeviceEventRxPtr.asFunction< - _ClientDeviceEventRxReturn Function( + int Function( int, )>(); late final _clientSubscribeToTypingEventStreamPtr = _lookup< @@ -55382,21 +55382,17 @@ class Client { } /// Return the event handler that new device was found or existing device was changed - Stream? deviceEventRx() { + Stream deviceEventRx() { var tmp0 = 0; tmp0 = _box.borrow(); final tmp1 = _api._clientDeviceEventRx( tmp0, ); - final tmp3 = tmp1.arg0; - final tmp4 = tmp1.arg1; - if (tmp3 == 0) { - return null; - } - final ffi.Pointer tmp4_0 = ffi.Pointer.fromAddress(tmp4); - final tmp4_1 = _Box(_api, tmp4_0, "__Client_device_event_rx_stream_drop"); - tmp4_1._finalizer = _api._registerFinalizer(tmp4_1); - final tmp2 = _nativeStream(tmp4_1, _api.__clientDeviceEventRxStreamPoll); + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__Client_device_event_rx_stream_drop"); + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeStream(tmp3_1, _api.__clientDeviceEventRxStreamPoll); return tmp2; } @@ -61490,13 +61486,6 @@ class _ClientVerificationEventRxReturn extends ffi.Struct { external int arg1; } -class _ClientDeviceEventRxReturn extends ffi.Struct { - @ffi.Uint8() - external int arg0; - @ffi.IntPtr() - external int arg1; -} - class _InvitationOriginServerTsReturn extends ffi.Struct { @ffi.Uint8() external int arg0; From 7dd1f3cb402341a73ae84015962c19615969eebe Mon Sep 17 00:00:00 2001 From: bitfriend Date: Mon, 9 Dec 2024 22:10:27 +0800 Subject: [PATCH 02/10] Wrap receiver in broadcast so that verification_event_rx can be called multiple times --- .../cross_signing/widgets/cross_signing.dart | 35 ++- app/lib/features/main/app_shell.dart | 5 +- native/acter/api.rsh | 20 +- native/acter/src/api/device.rs | 5 +- native/acter/src/api/verification.rs | 294 ++++++------------ native/test/src/tests/verification.rs | 69 ++-- .../rust_sdk/lib/acter_flutter_sdk_ffi.dart | 282 ++++++++++------- 7 files changed, 342 insertions(+), 368 deletions(-) diff --git a/app/lib/features/cross_signing/widgets/cross_signing.dart b/app/lib/features/cross_signing/widgets/cross_signing.dart index 1c1a74bde932..f038bc4f9132 100644 --- a/app/lib/features/cross_signing/widgets/cross_signing.dart +++ b/app/lib/features/cross_signing/widgets/cross_signing.dart @@ -19,8 +19,11 @@ final _log = Logger('a3::cross_signing::widget'); // this widget has no elements // it just pops up stage dialogs for verification +@immutable class CrossSigning extends ConsumerStatefulWidget { - const CrossSigning({super.key}); + final Client client; + + const CrossSigning({super.key, required this.client}); @override ConsumerState createState() => CrossSigningState(); @@ -111,7 +114,7 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => RequestCreatedView( onCancel: (BuildContext context) async { // cancel verification request launched by this device - await event.cancelVerificationRequest(); + await event.cancelVerificationRequest(widget.client); }, ), isDismissible: false, @@ -137,11 +140,13 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => RequestReadyView( isVerifier: isVerifier, onCancel: (BuildContext context) async { - await event.cancelVerificationRequest(); // occurs request.cancelled + await event.cancelVerificationRequest( + widget.client); // occurs request.cancelled }, onAccept: (BuildContext context) async { // start sas verification from this device - await event.startSasVerification(); // occurs request.transitioned + await event.startSasVerification( + widget.client); // occurs request.transitioned }, ), isDismissible: false, @@ -227,11 +232,11 @@ class CrossSigningState extends ConsumerState { sender: event.sender(), onCancel: (BuildContext context) async { // cancel verification request from other device - await event.cancelVerificationRequest(); + await event.cancelVerificationRequest(widget.client); }, onAccept: (BuildContext context) async { // accept verification request from other device - await event.acceptVerificationRequest(); + await event.acceptVerificationRequest(widget.client); }, ), isDismissible: false, @@ -251,7 +256,7 @@ class CrossSigningState extends ConsumerState { if (nav.canPop()) nav.pop(); // accept sas that verifier started - event.acceptSasVerification(); + event.acceptSasVerification(widget.client); // open sas.started dialog showModalBottomSheet( @@ -259,7 +264,7 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => SasStartedView( isVerifier: isVerifier, onCancel: (BuildContext context) async { - await event.cancelSasVerification(); + await event.cancelSasVerification(widget.client); }, ), isDismissible: false, @@ -335,22 +340,22 @@ class CrossSigningState extends ConsumerState { isVerifier: isVerifier, emojis: event.emojis(), onCancel: (BuildContext context) async { - await event.cancelSasVerification(); + await event.cancelSasVerification(widget.client); }, onMatch: (BuildContext context) async { _log.info('sas.keys_exchanged - match'); - await event.confirmSasVerification(); + await event.confirmSasVerification(widget.client); }, onMismatch: (BuildContext context) async { _log.info('sas.keys_exchanged - mismatch'); - await event.mismatchSasVerification(); + await event.mismatchSasVerification(widget.client); }, ), isDismissible: false, ); } else { // fetch emojis - event.getEmojis().then((emojis) { + event.getEmojis(widget.client).then((emojis) { if (!context.mounted) return; // open sas.keys_exchanged dialog showModalBottomSheet( @@ -361,15 +366,15 @@ class CrossSigningState extends ConsumerState { isVerifier: isVerifier, emojis: emojis, onCancel: (BuildContext context) async { - await event.cancelSasVerification(); + await event.cancelSasVerification(widget.client); }, onMatch: (BuildContext context) async { _log.info('sas.keys_exchanged - match'); - await event.confirmSasVerification(); + await event.confirmSasVerification(widget.client); }, onMismatch: (BuildContext context) async { _log.info('sas.keys_exchanged - mismatch'); - await event.mismatchSasVerification(); + await event.mismatchSasVerification(widget.client); }, ), isDismissible: false, diff --git a/app/lib/features/main/app_shell.dart b/app/lib/features/main/app_shell.dart index 08d290763a81..b3aab50deec7 100644 --- a/app/lib/features/main/app_shell.dart +++ b/app/lib/features/main/app_shell.dart @@ -130,7 +130,8 @@ class AppShellState extends ConsumerState { @override Widget build(BuildContext context) { // get platform of context. - if (ref.watch(clientProvider) == null) { + final client = ref.watch(clientProvider); + if (client == null) { // at the very startup we might not yet have a client loaded // show a loading spinner meanwhile. return const Scaffold( @@ -163,7 +164,7 @@ class AppShellState extends ConsumerState { controller: screenshotController, child: Column( children: [ - const CrossSigning(), + CrossSigning(client: client), Expanded( child: buildBody(context), ), diff --git a/native/acter/api.rsh b/native/acter/api.rsh index bc84e833981b..a4507427b632 100644 --- a/native/acter/api.rsh +++ b/native/acter/api.rsh @@ -2803,7 +2803,7 @@ object Client { fn logout() -> Future>; /// Get the verification event receiver - fn verification_event_rx() -> Option>; + fn verification_event_rx() -> Stream; /// Get session manager that returns all/verified/unverified/inactive session list fn session_manager() -> SessionManager; @@ -3108,32 +3108,32 @@ object VerificationEvent { fn emojis() -> Vec; /// Get emoji array - fn get_emojis() -> Future>>; + fn get_emojis(client: Client) -> Future>>; /// Bob accepts the verification request from Alice - fn accept_verification_request() -> Future>; + fn accept_verification_request(client: Client) -> Future>; /// Bob cancels the verification request from Alice /// alternative of terminate_verification - fn cancel_verification_request() -> Future>; + fn cancel_verification_request(client: Client) -> Future>; /// Bob accepts the verification request from Alice with specified method - fn accept_verification_request_with_method(method: string) -> Future>; + fn accept_verification_request_with_method(client: Client, method: string) -> Future>; /// Alice starts the SAS verification - fn start_sas_verification() -> Future>; + fn start_sas_verification(client: Client) -> Future>; /// Bob accepts the SAS verification - fn accept_sas_verification() -> Future>; + fn accept_sas_verification(client: Client) -> Future>; /// Bob cancels the SAS verification - fn cancel_sas_verification() -> Future>; + fn cancel_sas_verification(client: Client) -> Future>; /// Alice says to Bob that SAS verification matches and vice versa - fn confirm_sas_verification() -> Future>; + fn confirm_sas_verification(client: Client) -> Future>; /// Alice says to Bob that SAS verification doesn’t match and vice versa - fn mismatch_sas_verification() -> Future>; + fn mismatch_sas_verification(client: Client) -> Future>; } object VerificationEmoji { diff --git a/native/acter/src/api/device.rs b/native/acter/src/api/device.rs index 9c3c5c9d8577..43afd746e18c 100644 --- a/native/acter/src/api/device.rs +++ b/native/acter/src/api/device.rs @@ -9,10 +9,7 @@ use std::{ sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use tokio::sync::{ - broadcast::{channel, Receiver, Sender}, - Mutex, -}; +use tokio::sync::broadcast::{channel, Receiver, Sender}; use tokio_stream::wrappers::BroadcastStream; use tracing::{error, info}; diff --git a/native/acter/src/api/verification.rs b/native/acter/src/api/verification.rs index 82fc72b33594..5f7e26f91e0a 100644 --- a/native/acter/src/api/verification.rs +++ b/native/acter/src/api/verification.rs @@ -1,8 +1,5 @@ use anyhow::{bail, Context, Result}; -use futures::{ - channel::mpsc::{channel, Receiver, Sender}, - stream::StreamExt, -}; +use futures::stream::{Stream, StreamExt}; use matrix_sdk::{ config::SyncSettings, encryption::verification::{ @@ -23,7 +20,7 @@ use matrix_sdk_base::ruma::{ room::message::{MessageType, OriginalSyncRoomMessageEvent}, AnyToDeviceEvent, EventContent, }, - OwnedDeviceId, OwnedUserId, + OwnedDeviceId, OwnedUserId, UserId, }; use std::{ collections::HashMap, @@ -31,18 +28,17 @@ use std::{ sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; -use tokio::sync::Mutex; +use tokio::sync::broadcast::{channel, Receiver, Sender}; +use tokio_stream::wrappers::BroadcastStream; use tracing::{error, info}; use super::{client::Client, common::DeviceRecord, RUNTIME}; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct VerificationEvent { - client: SdkClient, - controller: VerificationController, event_type: String, flow_id: String, - sender: OwnedUserId, + sender: String, /// event content content: HashMap, /// emoji array @@ -50,19 +46,11 @@ pub struct VerificationEvent { } impl VerificationEvent { - pub(crate) fn new( - client: SdkClient, - controller: VerificationController, - event_type: String, - flow_id: String, - sender: OwnedUserId, - ) -> Self { + pub(crate) fn new(event_type: String, flow_id: String, sender: OwnedUserId) -> Self { VerificationEvent { - client, - controller, event_type, flow_id, - sender, + sender: sender.to_string(), content: Default::default(), emojis: Default::default(), } @@ -98,13 +86,14 @@ impl VerificationEvent { } // when other device triggered verification of this device, it can get emojis from remote server - pub async fn get_emojis(&self) -> Result> { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn get_emojis(&self, client: Box) -> Result> { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client + .core + .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -122,14 +111,14 @@ impl VerificationEvent { .await? } - pub async fn accept_verification_request(&self) -> Result { - let client = self.client.clone(); - let controller = self.controller.clone(); - let sender = self.sender.clone(); + pub async fn accept_verification_request(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client + .core + .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -148,13 +137,14 @@ impl VerificationEvent { } // alternative of terminate_verification - pub async fn cancel_verification_request(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn cancel_verification_request(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client + .core + .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -168,15 +158,19 @@ impl VerificationEvent { .await? } - pub async fn accept_verification_request_with_method(&self, method: String) -> Result { - let client = self.client.clone(); - let controller = self.controller.clone(); - let sender = self.sender.clone(); + pub async fn accept_verification_request_with_method( + &self, + client: Box, + method: String, + ) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); let values = vec![VerificationMethod::from(method.as_str())]; RUNTIME .spawn(async move { let Some(request) = client + .core + .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -194,13 +188,14 @@ impl VerificationEvent { .await? } - pub async fn start_sas_verification(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn start_sas_verification(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client + .core + .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -214,14 +209,14 @@ impl VerificationEvent { .await? } - pub async fn accept_sas_verification(&self) -> Result { - let client = self.client.clone(); - let controller = self.controller.clone(); - let sender = self.sender.clone(); + pub async fn accept_sas_verification(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client + .core + .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -240,13 +235,14 @@ impl VerificationEvent { .await? } - pub async fn cancel_sas_verification(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn cancel_sas_verification(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client + .core + .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -261,24 +257,28 @@ impl VerificationEvent { } #[cfg(feature = "testing")] - pub async fn send_verification_key(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn send_verification_key(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; RUNTIME .spawn(async move { - client.sync_once(SyncSettings::default()).await?; // send_outgoing_requests is called there + client + .core + .client() + .sync_once(SyncSettings::default()) + .await?; // send_outgoing_requests is called there Ok(true) }) .await? } - pub async fn confirm_sas_verification(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn confirm_sas_verification(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client + .core + .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -292,13 +292,14 @@ impl VerificationEvent { .await? } - pub async fn mismatch_sas_verification(&self) -> Result { - let client = self.client.clone(); - let sender = self.sender.clone(); + pub async fn mismatch_sas_verification(&self, client: Box) -> Result { + let sender = UserId::parse(self.sender.clone())?; let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client + .core + .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -339,11 +340,11 @@ impl VerificationEmoji { async fn request_verification_handler( client: Client, - mut controller: VerificationController, request: VerificationRequest, flow_id: String, sender: OwnedUserId, ) -> Result<()> { + let controller = client.verification_controller.clone(); let mut stream = request.changes(); while let Some(state) = stream.next().await { match state { @@ -351,20 +352,14 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Created".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); let methods = our_methods .iter() .map(|x| x.to_string()) .collect::>() .join(","); msg.set_content("our_methods".to_string(), methods); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -375,13 +370,7 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Requested".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); let methods = their_methods .iter() .map(|x| x.to_string()) @@ -392,7 +381,7 @@ async fn request_verification_handler( "other_device_id".to_string(), other_device_data.device_id().to_string(), ); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -404,13 +393,7 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Ready".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); let methods = their_methods .iter() .map(|x| x.to_string()) @@ -427,7 +410,7 @@ async fn request_verification_handler( "other_device_id".to_string(), other_device_data.device_id().to_string(), ); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -436,14 +419,8 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Transitioned".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); - if let Err(e) = controller.event_tx.try_send(msg) { + let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -452,14 +429,8 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Done".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); - if let Err(e) = controller.event_tx.try_send(msg) { + let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } break; @@ -468,19 +439,13 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Cancelled".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); msg.set_content( "cancel_code".to_string(), cancel_info.cancel_code().to_string(), ); msg.set_content("reason".to_string(), cancel_info.reason().to_string()); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } break; @@ -492,11 +457,11 @@ async fn request_verification_handler( async fn sas_verification_handler( client: Client, - mut controller: VerificationController, sas: SasVerification, flow_id: String, sender: OwnedUserId, ) -> Result<()> { + let controller = client.verification_controller.clone(); let mut stream = sas.changes(); while let Some(state) = stream.next().await { match state { @@ -504,13 +469,7 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::KeysExchanged".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); if let Some(auth_string) = emojis { let sequence = auth_string .emojis @@ -527,7 +486,7 @@ async fn sas_verification_handler( } }; msg.set_content("decimals".to_string(), value); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -538,13 +497,7 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Done".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); let devices = verified_devices .iter() .map(|x| x.device_id().to_string()) @@ -555,7 +508,7 @@ async fn sas_verification_handler( .map(|x| x.user_id().to_string()) .collect::>(); msg.set_content("verified_identities".to_string(), identifiers.join(",")); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } break; @@ -564,19 +517,13 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Cancelled".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); msg.set_content( "cancel_code".to_string(), cancel_info.cancel_code().to_string(), ); msg.set_content("reason".to_string(), cancel_info.reason().to_string()); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } break; @@ -585,13 +532,7 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Started".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); let key_agreement_protocols = protocols .key_agreement_protocols .iter() @@ -625,7 +566,7 @@ async fn sas_verification_handler( "short_authentication_string".to_string(), short_authentication_string.join(","), ); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -633,13 +574,7 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Accepted".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); + let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); msg.set_content( "key_agreement_protocol".to_string(), accepted_protocols.key_agreement_protocol.to_string(), @@ -651,7 +586,7 @@ async fn sas_verification_handler( .map(|x| x.to_string()) .collect::>(); msg.set_content("short_auth_string".to_string(), short_auth_string.join(",")); - if let Err(e) = controller.event_tx.try_send(msg) { + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -659,14 +594,8 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Confirmed".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new( - client.deref().clone(), - controller.clone(), - event_type, - flow_id.clone(), - sender.clone(), - ); - if let Err(e) = controller.event_tx.try_send(msg) { + let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } } @@ -679,7 +608,7 @@ async fn sas_verification_handler( #[derive(Clone, Debug)] pub(crate) struct VerificationController { event_tx: Sender, - event_rx: Arc>>>, + event_rx: Arc>, sync_key_verification_request_handle: Option, any_to_device_handle: Option, } @@ -689,7 +618,7 @@ impl VerificationController { let (tx, rx) = channel::(10); // dropping after more than 10 items queued VerificationController { event_tx: tx, - event_rx: Arc::new(Mutex::new(Some(rx))), + event_rx: Arc::new(rx), sync_key_verification_request_handle: None, any_to_device_handle: None, } @@ -708,8 +637,6 @@ impl VerificationController { let event_type = ev.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), ev.event_id.to_string(), ev.sender, @@ -725,7 +652,7 @@ impl VerificationController { msg.set_content("to".to_string(), content.to.to_string()); // this may be the past event occurred when device was off // so this event has no timestamp field unlike AnyToDeviceEvent::KeyVerificationRequest - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", ev.event_id, e); } // from then on, accept_verification_request takes over @@ -756,8 +683,6 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -766,7 +691,7 @@ impl VerificationController { let methods = evt.content.methods.iter().map(|x| x.to_string()).collect::>(); msg.set_content("methods".to_string(), methods.join(",")); msg.set_content("timestamp".to_string(), evt.content.timestamp.get().to_string()); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -775,8 +700,6 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -784,7 +707,7 @@ impl VerificationController { msg.set_content("from_device".to_string(), evt.content.from_device.to_string()); let methods = evt.content.methods.iter().map(|x| x.to_string()).collect::>(); msg.set_content("methods".to_string(), methods.join(",")); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -793,8 +716,6 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -839,7 +760,7 @@ impl VerificationController { } _ => {} } - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -848,14 +769,12 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); msg.set_content("key".to_string(), evt.content.key.to_string()); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -864,8 +783,6 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -882,7 +799,7 @@ impl VerificationController { msg.set_content("short_authentication_string".to_string(), short_authentication_string.join(",")); msg.set_content("commitment".to_string(), content.commitment.to_string()); } - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -891,15 +808,13 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); msg.set_content("code".to_string(), evt.content.code.to_string()); msg.set_content("reason".to_string(), evt.content.reason); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -908,8 +823,6 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -923,7 +836,7 @@ impl VerificationController { } }; msg.set_content("mac".to_string(), mac); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -932,13 +845,11 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let msg = VerificationEvent::new( - c, - me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); - if let Err(e) = me.event_tx.try_send(msg) { + if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } } @@ -1077,11 +988,9 @@ impl SessionManager { } impl Client { - pub fn verification_event_rx(&self) -> Option> { - match self.verification_controller.event_rx.try_lock() { - Ok(mut r) => r.take(), - Err(e) => None, - } + pub fn verification_event_rx(&self) -> impl Stream { + BroadcastStream::new(self.verification_controller.event_rx.resubscribe()) + .map(|o| o.unwrap_or_default()) } pub fn session_manager(&self) -> SessionManager { @@ -1092,7 +1001,6 @@ impl Client { pub async fn request_verification(&self, dev_id: String) -> Result { let client = self.core.client().clone(); - let controller = self.verification_controller.clone(); let user_id = self.user_id()?; RUNTIME @@ -1112,8 +1020,6 @@ impl Client { let flow_id = request.flow_id().to_owned(); info!("requested verification - flow_id: {}", flow_id.clone()); let msg = VerificationEvent::new( - client, - controller, "VerificationRequestState::Created".to_owned(), flow_id, user_id, @@ -1148,7 +1054,6 @@ impl Client { pub async fn install_request_event_handler(&self, flow_id: String) -> Result { let me = self.clone(); - let controller = self.verification_controller.clone(); let sender = self.user_id()?; RUNTIME @@ -1160,9 +1065,7 @@ impl Client { .get_verification_request(&sender, &flow_id) .await .context("Could not get verification request")?; // request may be timed out - tokio::spawn(request_verification_handler( - me, controller, request, flow_id, sender, - )); + tokio::spawn(request_verification_handler(me, request, flow_id, sender)); Ok(true) }) .await? @@ -1170,7 +1073,6 @@ impl Client { pub async fn install_sas_event_handler(&self, flow_id: String) -> Result { let me = self.clone(); - let controller = self.verification_controller.clone(); let sender = self.user_id()?; RUNTIME @@ -1185,9 +1087,7 @@ impl Client { // request may be timed out bail!("Could not get verification object") }; - tokio::spawn(sas_verification_handler( - me, controller, sas, flow_id, sender, - )); + tokio::spawn(sas_verification_handler(me, sas, flow_id, sender)); Ok(true) }) .await? diff --git a/native/test/src/tests/verification.rs b/native/test/src/tests/verification.rs index 051b0c0104e4..67b96892a618 100644 --- a/native/test/src/tests/verification.rs +++ b/native/test/src/tests/verification.rs @@ -1,16 +1,21 @@ use acter::api::VerificationEvent; use anyhow::Result; -use futures::{channel::mpsc::Receiver, stream::StreamExt}; +use futures::{ + pin_mut, + stream::{Stream, StreamExt}, + FutureExt, +}; use tracing::info; use crate::utils::random_user; -fn wait_for_verification_event( - rx: &mut Receiver, +async fn wait_for_verification_event( + rx: impl Stream, name: &str, ) -> VerificationEvent { + pin_mut!(rx); loop { - if let Ok(Some(event)) = rx.try_next() { + if let Some(event) = rx.next().now_or_never().flatten() { if event.event_type() == name { return event; } @@ -35,16 +40,16 @@ async fn interactive_verification_started_from_request() -> Result<()> { // we have two devices logged in // sync both up to ensure they’ve seen the other device - let mut alice_device_rx = alice.device_event_rx().unwrap(); + let mut alice_device_rx = alice.device_event_rx(); let syncer = alice.start_sync(); let mut first_synced = syncer.first_synced_rx(); while first_synced.next().await != Some(true) {} // let’s wait for it to have synced - let mut alice_rx = alice.verification_event_rx().unwrap(); + let mut alice_rx = alice.verification_event_rx(); let syncer = bob.start_sync(); let mut first_synced = syncer.first_synced_rx(); while first_synced.next().await != Some(true) {} // let’s wait for it to have synced - let mut bob_rx = bob.verification_event_rx().unwrap(); + let mut bob_rx = bob.verification_event_rx(); // according to alice bob is not verfied: assert!(!alice.verified_device(bob_device_id.to_string()).await?); @@ -57,7 +62,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // Alice gets notified that new device (Bob) was logged in loop { - if let Ok(Some(_event)) = alice_device_rx.try_next() { + if let Some(_event) = alice_device_rx.next().await { if let Ok(_devices) = alice.device_records(false).await { // Alice sends a verification request with her desired methods to Bob alice @@ -75,107 +80,113 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Bob’s device: // Bob receives the request event from Alice - let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.request"); + let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.request").await; // Bob accepts the request, sending a Ready request event - .accept_verification_request_with_method("m.sas.v1".to_string()) + .accept_verification_request_with_method(Box::new(bob.clone()), "m.sas.v1".to_string()) .await?; // And also immediately sends a start request - let started = event.start_sas_verification().await?; + let started = event.start_sas_verification(Box::new(bob.clone())).await?; assert!(started, "bob failed to start sas"); // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the ready event from Bob - let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.ready"); + let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.ready").await; // Alice immediately sends a start request - let started = event.start_sas_verification().await?; + let started = event + .start_sas_verification(Box::new(alice.clone())) + .await?; assert!(started, "alice failed to start sas verification"); // Now Alice receives the start event from Bob // Without this loop, sometimes the cancel event follows the start event - wait_for_verification_event(&mut alice_rx, "m.key.verification.start"); + wait_for_verification_event(&mut alice_rx, "m.key.verification.start").await; // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the start event from Alice - let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.start"); + let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.start").await; // Bob accepts it - let accepted = event.accept_sas_verification().await?; + let accepted = event.accept_sas_verification(Box::new(bob.clone())).await?; assert!(accepted, "bob failed to accept sas verification"); // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the accept event from Bob - let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.accept"); + let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.accept").await; // Alice sends a key - event.send_verification_key().await?; + event.send_verification_key(Box::new(alice.clone())).await?; // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the key event from Alice - let bob_event = wait_for_verification_event(&mut bob_rx, "m.key.verification.key"); + let bob_event = wait_for_verification_event(&mut bob_rx, "m.key.verification.key").await; // Bob gets the verification key from event - let emojis_from_alice = bob_event.get_emojis().await?; + let emojis_from_alice = bob_event.get_emojis(Box::new(bob.clone())).await?; info!("emojis from alice: {:?}", emojis_from_alice); // Bob sends a key - bob_event.send_verification_key().await?; + bob_event + .send_verification_key(Box::new(bob.clone())) + .await?; // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the key event from Bob - let alice_event = wait_for_verification_event(&mut alice_rx, "m.key.verification.key"); + let alice_event = wait_for_verification_event(&mut alice_rx, "m.key.verification.key").await; // Alice gets the verification key from event - let emojis_from_bob = alice_event.get_emojis().await?; + let emojis_from_bob = alice_event.get_emojis(Box::new(alice.clone())).await?; info!("emojis from bob: {:?}", emojis_from_bob); // ---------------------------------------------------------------------------- // On Bob’s device: // Bob first confirms that the emojis match and sends the mac event... - bob_event.confirm_sas_verification().await?; + bob_event.confirm_sas_verification(Box::new(bob)).await?; // ---------------------------------------------------------------------------- // On Alice’s device: // Alice first confirms that the emojis match and sends the mac event... - alice_event.confirm_sas_verification().await?; + alice_event + .confirm_sas_verification(Box::new(alice)) + .await?; // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the mac event from Alice - wait_for_verification_event(&mut bob_rx, "m.key.verification.mac"); + wait_for_verification_event(&mut bob_rx, "m.key.verification.mac").await; // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the mac event from Bob - wait_for_verification_event(&mut alice_rx, "m.key.verification.mac"); + wait_for_verification_event(&mut alice_rx, "m.key.verification.mac").await; // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the done event from Alice - wait_for_verification_event(&mut bob_rx, "m.key.verification.done"); + wait_for_verification_event(&mut bob_rx, "m.key.verification.done").await; // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the done event from Bob - wait_for_verification_event(&mut alice_rx, "m.key.verification.done"); + wait_for_verification_event(&mut alice_rx, "m.key.verification.done").await; Ok(()) } diff --git a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart index f964c877d979..f50d60feaf5a 100644 --- a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart +++ b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart @@ -26979,13 +26979,13 @@ class Api { )>(); late final _clientVerificationEventRxPtr = _lookup< ffi.NativeFunction< - _ClientVerificationEventRxReturn Function( + ffi.IntPtr Function( ffi.IntPtr, )>>("__Client_verification_event_rx"); late final _clientVerificationEventRx = _clientVerificationEventRxPtr.asFunction< - _ClientVerificationEventRxReturn Function( + int Function( int, )>(); late final _clientSessionManagerPtr = _lookup< @@ -28261,38 +28261,45 @@ class Api { ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_get_emojis"); late final _verificationEventGetEmojis = _verificationEventGetEmojisPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventAcceptVerificationRequestPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_accept_verification_request"); late final _verificationEventAcceptVerificationRequest = _verificationEventAcceptVerificationRequestPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventCancelVerificationRequestPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_cancel_verification_request"); late final _verificationEventCancelVerificationRequest = _verificationEventCancelVerificationRequestPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventAcceptVerificationRequestWithMethodPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( + ffi.IntPtr, ffi.IntPtr, ffi.IntPtr, ffi.UintPtr, @@ -28306,61 +28313,72 @@ class Api { int, int, int, + int, )>(); late final _verificationEventStartSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_start_sas_verification"); late final _verificationEventStartSasVerification = _verificationEventStartSasVerificationPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventAcceptSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_accept_sas_verification"); late final _verificationEventAcceptSasVerification = _verificationEventAcceptSasVerificationPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventCancelSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_cancel_sas_verification"); late final _verificationEventCancelSasVerification = _verificationEventCancelSasVerificationPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventConfirmSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_confirm_sas_verification"); late final _verificationEventConfirmSasVerification = _verificationEventConfirmSasVerificationPtr.asFunction< int Function( int, + int, )>(); late final _verificationEventMismatchSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, + ffi.IntPtr, )>>("__VerificationEvent_mismatch_sas_verification"); late final _verificationEventMismatchSasVerification = _verificationEventMismatchSasVerificationPtr.asFunction< int Function( int, + int, )>(); late final _verificationEmojiSymbolPtr = _lookup< ffi.NativeFunction< @@ -55243,23 +55261,19 @@ class Client { } /// Get the verification event receiver - Stream? verificationEventRx() { + Stream verificationEventRx() { var tmp0 = 0; tmp0 = _box.borrow(); final tmp1 = _api._clientVerificationEventRx( tmp0, ); - final tmp3 = tmp1.arg0; - final tmp4 = tmp1.arg1; - if (tmp3 == 0) { - return null; - } - final ffi.Pointer tmp4_0 = ffi.Pointer.fromAddress(tmp4); - final tmp4_1 = - _Box(_api, tmp4_0, "__Client_verification_event_rx_stream_drop"); - tmp4_1._finalizer = _api._registerFinalizer(tmp4_1); + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = + _Box(_api, tmp3_0, "__Client_verification_event_rx_stream_drop"); + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); final tmp2 = - _nativeStream(tmp4_1, _api.__clientVerificationEventRxStreamPoll); + _nativeStream(tmp3_1, _api.__clientVerificationEventRxStreamPoll); return tmp2; } @@ -57908,174 +57922,227 @@ class VerificationEvent { } /// Get emoji array - Future getEmojis() { + Future getEmojis( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventGetEmojis( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventGetEmojis( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = - _Box(_api, tmp3_0, "__VerificationEvent_get_emojis_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = - _nativeFuture(tmp3_1, _api.__verificationEventGetEmojisFuturePoll); - return tmp2; + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = + _Box(_api, tmp5_0, "__VerificationEvent_get_emojis_future_drop"); + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = + _nativeFuture(tmp5_1, _api.__verificationEventGetEmojisFuturePoll); + return tmp4; } /// Bob accepts the verification request from Alice - Future acceptVerificationRequest() { + Future acceptVerificationRequest( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventAcceptVerificationRequest( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventAcceptVerificationRequest( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_accept_verification_request_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventAcceptVerificationRequestFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventAcceptVerificationRequestFuturePoll); + return tmp4; } /// Bob cancels the verification request from Alice /// alternative of terminate_verification - Future cancelVerificationRequest() { + Future cancelVerificationRequest( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventCancelVerificationRequest( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventCancelVerificationRequest( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_cancel_verification_request_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventCancelVerificationRequestFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventCancelVerificationRequestFuturePoll); + return tmp4; } /// Bob accepts the verification request from Alice with specified method Future acceptVerificationRequestWithMethod( + Client client, String method, ) { - final tmp1 = method; + final tmp1 = client; + final tmp3 = method; var tmp0 = 0; var tmp2 = 0; - var tmp3 = 0; var tmp4 = 0; + var tmp5 = 0; + var tmp6 = 0; tmp0 = _box.borrow(); - final tmp1_0 = utf8.encode(tmp1); - tmp3 = tmp1_0.length; + tmp2 = tmp1._box.move(); + final tmp3_0 = utf8.encode(tmp3); + tmp5 = tmp3_0.length; - final ffi.Pointer tmp2_0 = _api.__allocate(tmp3 * 1, 1); - final Uint8List tmp2_1 = tmp2_0.asTypedList(tmp3); - tmp2_1.setAll(0, tmp1_0); - tmp2 = tmp2_0.address; - tmp4 = tmp3; - final tmp5 = _api._verificationEventAcceptVerificationRequestWithMethod( + final ffi.Pointer tmp4_0 = _api.__allocate(tmp5 * 1, 1); + final Uint8List tmp4_1 = tmp4_0.asTypedList(tmp5); + tmp4_1.setAll(0, tmp3_0); + tmp4 = tmp4_0.address; + tmp6 = tmp5; + final tmp7 = _api._verificationEventAcceptVerificationRequestWithMethod( tmp0, tmp2, - tmp3, tmp4, + tmp5, + tmp6, ); - final tmp7 = tmp5; - final ffi.Pointer tmp7_0 = ffi.Pointer.fromAddress(tmp7); - final tmp7_1 = _Box(_api, tmp7_0, + final tmp9 = tmp7; + final ffi.Pointer tmp9_0 = ffi.Pointer.fromAddress(tmp9); + final tmp9_1 = _Box(_api, tmp9_0, "__VerificationEvent_accept_verification_request_with_method_future_drop"); - tmp7_1._finalizer = _api._registerFinalizer(tmp7_1); - final tmp6 = _nativeFuture(tmp7_1, + tmp9_1._finalizer = _api._registerFinalizer(tmp9_1); + final tmp8 = _nativeFuture(tmp9_1, _api.__verificationEventAcceptVerificationRequestWithMethodFuturePoll); - return tmp6; + return tmp8; } /// Alice starts the SAS verification - Future startSasVerification() { + Future startSasVerification( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventStartSasVerification( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventStartSasVerification( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box( - _api, tmp3_0, "__VerificationEvent_start_sas_verification_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventStartSasVerificationFuturePoll); - return tmp2; + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box( + _api, tmp5_0, "__VerificationEvent_start_sas_verification_future_drop"); + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventStartSasVerificationFuturePoll); + return tmp4; } /// Bob accepts the SAS verification - Future acceptSasVerification() { + Future acceptSasVerification( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventAcceptSasVerification( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventAcceptSasVerification( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_accept_sas_verification_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventAcceptSasVerificationFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventAcceptSasVerificationFuturePoll); + return tmp4; } /// Bob cancels the SAS verification - Future cancelSasVerification() { + Future cancelSasVerification( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventCancelSasVerification( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventCancelSasVerification( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_cancel_sas_verification_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventCancelSasVerificationFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventCancelSasVerificationFuturePoll); + return tmp4; } /// Alice says to Bob that SAS verification matches and vice versa - Future confirmSasVerification() { + Future confirmSasVerification( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventConfirmSasVerification( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventConfirmSasVerification( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_confirm_sas_verification_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventConfirmSasVerificationFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventConfirmSasVerificationFuturePoll); + return tmp4; } /// Alice says to Bob that SAS verification doesn’t match and vice versa - Future mismatchSasVerification() { + Future mismatchSasVerification( + Client client, + ) { + final tmp1 = client; var tmp0 = 0; + var tmp2 = 0; tmp0 = _box.borrow(); - final tmp1 = _api._verificationEventMismatchSasVerification( + tmp2 = tmp1._box.move(); + final tmp3 = _api._verificationEventMismatchSasVerification( tmp0, + tmp2, ); - final tmp3 = tmp1; - final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); - final tmp3_1 = _Box(_api, tmp3_0, + final tmp5 = tmp3; + final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); + final tmp5_1 = _Box(_api, tmp5_0, "__VerificationEvent_mismatch_sas_verification_future_drop"); - tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); - final tmp2 = _nativeFuture( - tmp3_1, _api.__verificationEventMismatchSasVerificationFuturePoll); - return tmp2; + tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); + final tmp4 = _nativeFuture( + tmp5_1, _api.__verificationEventMismatchSasVerificationFuturePoll); + return tmp4; } /// Manually drops the object and unregisters the FinalizableHandle. @@ -61479,13 +61546,6 @@ class _ClientDmWithUserReturn extends ffi.Struct { external int arg4; } -class _ClientVerificationEventRxReturn extends ffi.Struct { - @ffi.Uint8() - external int arg0; - @ffi.IntPtr() - external int arg1; -} - class _InvitationOriginServerTsReturn extends ffi.Struct { @ffi.Uint8() external int arg0; From 2e17fd5853d379a612c3597890e0099be6c21469 Mon Sep 17 00:00:00 2001 From: bitfriend Date: Mon, 9 Dec 2024 22:22:32 +0800 Subject: [PATCH 03/10] Fix lint error from git workflow --- app/lib/features/cross_signing/widgets/cross_signing.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/lib/features/cross_signing/widgets/cross_signing.dart b/app/lib/features/cross_signing/widgets/cross_signing.dart index f038bc4f9132..e066e396d348 100644 --- a/app/lib/features/cross_signing/widgets/cross_signing.dart +++ b/app/lib/features/cross_signing/widgets/cross_signing.dart @@ -140,13 +140,13 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => RequestReadyView( isVerifier: isVerifier, onCancel: (BuildContext context) async { - await event.cancelVerificationRequest( - widget.client); // occurs request.cancelled + // occurs request.cancelled + await event.cancelVerificationRequest(widget.client); }, onAccept: (BuildContext context) async { // start sas verification from this device - await event.startSasVerification( - widget.client); // occurs request.transitioned + // occurs request.transitioned + await event.startSasVerification(widget.client); }, ), isDismissible: false, From 30ea00e6de40e1ccf4add6f7b6a49263daca7135 Mon Sep 17 00:00:00 2001 From: bitfriend Date: Mon, 9 Dec 2024 23:11:50 +0800 Subject: [PATCH 04/10] Refactor code --- native/test/src/tests/verification.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/native/test/src/tests/verification.rs b/native/test/src/tests/verification.rs index 67b96892a618..a7a03925d0ab 100644 --- a/native/test/src/tests/verification.rs +++ b/native/test/src/tests/verification.rs @@ -9,7 +9,7 @@ use tracing::info; use crate::utils::random_user; -async fn wait_for_verification_event( +fn wait_for_verification_event( rx: impl Stream, name: &str, ) -> VerificationEvent { @@ -80,7 +80,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Bob’s device: // Bob receives the request event from Alice - let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.request").await; + let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.request"); // Bob accepts the request, sending a Ready request event @@ -94,7 +94,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Alice’s device: // Alice receives the ready event from Bob - let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.ready").await; + let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.ready"); // Alice immediately sends a start request let started = event @@ -104,13 +104,13 @@ async fn interactive_verification_started_from_request() -> Result<()> { // Now Alice receives the start event from Bob // Without this loop, sometimes the cancel event follows the start event - wait_for_verification_event(&mut alice_rx, "m.key.verification.start").await; + wait_for_verification_event(&mut alice_rx, "m.key.verification.start"); // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the start event from Alice - let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.start").await; + let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.start"); // Bob accepts it let accepted = event.accept_sas_verification(Box::new(bob.clone())).await?; @@ -120,7 +120,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Alice’s device: // Alice receives the accept event from Bob - let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.accept").await; + let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.accept"); // Alice sends a key event.send_verification_key(Box::new(alice.clone())).await?; @@ -129,7 +129,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Bob’s device: // Bob receives the key event from Alice - let bob_event = wait_for_verification_event(&mut bob_rx, "m.key.verification.key").await; + let bob_event = wait_for_verification_event(&mut bob_rx, "m.key.verification.key"); // Bob gets the verification key from event let emojis_from_alice = bob_event.get_emojis(Box::new(bob.clone())).await?; @@ -144,7 +144,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Alice’s device: // Alice receives the key event from Bob - let alice_event = wait_for_verification_event(&mut alice_rx, "m.key.verification.key").await; + let alice_event = wait_for_verification_event(&mut alice_rx, "m.key.verification.key"); // Alice gets the verification key from event let emojis_from_bob = alice_event.get_emojis(Box::new(alice.clone())).await?; @@ -168,25 +168,25 @@ async fn interactive_verification_started_from_request() -> Result<()> { // On Bob’s device: // Bob receives the mac event from Alice - wait_for_verification_event(&mut bob_rx, "m.key.verification.mac").await; + wait_for_verification_event(&mut bob_rx, "m.key.verification.mac"); // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the mac event from Bob - wait_for_verification_event(&mut alice_rx, "m.key.verification.mac").await; + wait_for_verification_event(&mut alice_rx, "m.key.verification.mac"); // ---------------------------------------------------------------------------- // On Bob’s device: // Bob receives the done event from Alice - wait_for_verification_event(&mut bob_rx, "m.key.verification.done").await; + wait_for_verification_event(&mut bob_rx, "m.key.verification.done"); // ---------------------------------------------------------------------------- // On Alice’s device: // Alice receives the done event from Bob - wait_for_verification_event(&mut alice_rx, "m.key.verification.done").await; + wait_for_verification_event(&mut alice_rx, "m.key.verification.done"); Ok(()) } From e5b88db6a2a85054f521606e1f47667faebcf2b0 Mon Sep 17 00:00:00 2001 From: bitfriend Date: Mon, 9 Dec 2024 23:27:51 +0800 Subject: [PATCH 05/10] Refactor code --- native/test/src/tests/verification.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/native/test/src/tests/verification.rs b/native/test/src/tests/verification.rs index a7a03925d0ab..b3b45632f42d 100644 --- a/native/test/src/tests/verification.rs +++ b/native/test/src/tests/verification.rs @@ -52,10 +52,12 @@ async fn interactive_verification_started_from_request() -> Result<()> { let mut bob_rx = bob.verification_event_rx(); // according to alice bob is not verfied: - assert!(!alice.verified_device(bob_device_id.to_string()).await?); + let bob_was_verified = alice.verified_device(bob_device_id.to_string()).await?; + assert!(!bob_was_verified); // according to bob alice is not verfied: - assert!(!bob.verified_device(alice_device_id.to_string()).await?); + let alice_was_verified = bob.verified_device(alice_device_id.to_string()).await?; + assert!(!alice_was_verified); // ---------------------------------------------------------------------------- // On Alice’s device: From 2e2689406697bbf8c3a46f50fe2bafc7a7d4789b Mon Sep 17 00:00:00 2001 From: bitfriend Date: Wed, 11 Dec 2024 01:38:56 +0800 Subject: [PATCH 06/10] Remove Default trait and return None on failure in BroadcastStream --- .../notifiers/verification_notifiers.dart | 13 +- .../cross_signing/widgets/cross_signing.dart | 34 +- app/lib/features/main/app_shell.dart | 5 +- native/acter/api.rsh | 25 +- native/acter/src/api.rs | 4 +- native/acter/src/api/verification.rs | 316 +++++++++++++----- native/test/src/tests/verification.rs | 36 +- .../rust_sdk/lib/acter_flutter_sdk_ffi.dart | 308 ++++++++--------- 8 files changed, 433 insertions(+), 308 deletions(-) diff --git a/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart b/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart index d4d1bab9a973..a280e7c69fd0 100644 --- a/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart +++ b/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:acter/common/extensions/options.dart'; import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'; import 'package:logging/logging.dart'; import 'package:riverpod/riverpod.dart'; @@ -17,8 +18,8 @@ class VerificationNotifier extends StateNotifier { final Ref ref; final Client client; - late Stream? _listener; - late StreamSubscription? _poller; + late Stream? _listener; + late StreamSubscription? _poller; VerificationNotifier({ required this.ref, @@ -30,7 +31,13 @@ class VerificationNotifier extends StateNotifier { void _init() { _listener = client.verificationEventRx(); // keep it resident in memory _poller = _listener?.listen( - _handleEvent, + (event) { + final data = event.data(); + data.map( + (event) => _handleEvent(event), + orElse: () => _log.info('invalid verification event'), + ); + }, onError: (e, s) { _log.severe('stream errored', e, s); }, diff --git a/app/lib/features/cross_signing/widgets/cross_signing.dart b/app/lib/features/cross_signing/widgets/cross_signing.dart index e066e396d348..7edb09dd3ccd 100644 --- a/app/lib/features/cross_signing/widgets/cross_signing.dart +++ b/app/lib/features/cross_signing/widgets/cross_signing.dart @@ -21,9 +21,7 @@ final _log = Logger('a3::cross_signing::widget'); // it just pops up stage dialogs for verification @immutable class CrossSigning extends ConsumerStatefulWidget { - final Client client; - - const CrossSigning({super.key, required this.client}); + const CrossSigning({super.key}); @override ConsumerState createState() => CrossSigningState(); @@ -114,7 +112,7 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => RequestCreatedView( onCancel: (BuildContext context) async { // cancel verification request launched by this device - await event.cancelVerificationRequest(widget.client); + await event.cancelVerificationRequest(); }, ), isDismissible: false, @@ -140,13 +138,11 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => RequestReadyView( isVerifier: isVerifier, onCancel: (BuildContext context) async { - // occurs request.cancelled - await event.cancelVerificationRequest(widget.client); + await event.cancelVerificationRequest(); // occurs request.cancelled }, onAccept: (BuildContext context) async { // start sas verification from this device - // occurs request.transitioned - await event.startSasVerification(widget.client); + await event.startSasVerification(); // occurs request.transitioned }, ), isDismissible: false, @@ -232,11 +228,11 @@ class CrossSigningState extends ConsumerState { sender: event.sender(), onCancel: (BuildContext context) async { // cancel verification request from other device - await event.cancelVerificationRequest(widget.client); + await event.cancelVerificationRequest(); }, onAccept: (BuildContext context) async { // accept verification request from other device - await event.acceptVerificationRequest(widget.client); + await event.acceptVerificationRequest(); }, ), isDismissible: false, @@ -256,7 +252,7 @@ class CrossSigningState extends ConsumerState { if (nav.canPop()) nav.pop(); // accept sas that verifier started - event.acceptSasVerification(widget.client); + event.acceptSasVerification(); // open sas.started dialog showModalBottomSheet( @@ -264,7 +260,7 @@ class CrossSigningState extends ConsumerState { builder: (BuildContext context) => SasStartedView( isVerifier: isVerifier, onCancel: (BuildContext context) async { - await event.cancelSasVerification(widget.client); + await event.cancelSasVerification(); }, ), isDismissible: false, @@ -340,22 +336,22 @@ class CrossSigningState extends ConsumerState { isVerifier: isVerifier, emojis: event.emojis(), onCancel: (BuildContext context) async { - await event.cancelSasVerification(widget.client); + await event.cancelSasVerification(); }, onMatch: (BuildContext context) async { _log.info('sas.keys_exchanged - match'); - await event.confirmSasVerification(widget.client); + await event.confirmSasVerification(); }, onMismatch: (BuildContext context) async { _log.info('sas.keys_exchanged - mismatch'); - await event.mismatchSasVerification(widget.client); + await event.mismatchSasVerification(); }, ), isDismissible: false, ); } else { // fetch emojis - event.getEmojis(widget.client).then((emojis) { + event.getEmojis().then((emojis) { if (!context.mounted) return; // open sas.keys_exchanged dialog showModalBottomSheet( @@ -366,15 +362,15 @@ class CrossSigningState extends ConsumerState { isVerifier: isVerifier, emojis: emojis, onCancel: (BuildContext context) async { - await event.cancelSasVerification(widget.client); + await event.cancelSasVerification(); }, onMatch: (BuildContext context) async { _log.info('sas.keys_exchanged - match'); - await event.confirmSasVerification(widget.client); + await event.confirmSasVerification(); }, onMismatch: (BuildContext context) async { _log.info('sas.keys_exchanged - mismatch'); - await event.mismatchSasVerification(widget.client); + await event.mismatchSasVerification(); }, ), isDismissible: false, diff --git a/app/lib/features/main/app_shell.dart b/app/lib/features/main/app_shell.dart index b3aab50deec7..3cef9df6f726 100644 --- a/app/lib/features/main/app_shell.dart +++ b/app/lib/features/main/app_shell.dart @@ -130,8 +130,7 @@ class AppShellState extends ConsumerState { @override Widget build(BuildContext context) { // get platform of context. - final client = ref.watch(clientProvider); - if (client == null) { + if (ref.watch(clientProvider) == null) { // at the very startup we might not yet have a client loaded // show a loading spinner meanwhile. return const Scaffold( @@ -164,7 +163,7 @@ class AppShellState extends ConsumerState { controller: screenshotController, child: Column( children: [ - CrossSigning(client: client), + CrossSigning(), Expanded( child: buildBody(context), ), diff --git a/native/acter/api.rsh b/native/acter/api.rsh index a4507427b632..07294b159d4a 100644 --- a/native/acter/api.rsh +++ b/native/acter/api.rsh @@ -2803,7 +2803,7 @@ object Client { fn logout() -> Future>; /// Get the verification event receiver - fn verification_event_rx() -> Stream; + fn verification_event_rx() -> Stream; /// Get session manager that returns all/verified/unverified/inactive session list fn session_manager() -> SessionManager; @@ -3108,32 +3108,37 @@ object VerificationEvent { fn emojis() -> Vec; /// Get emoji array - fn get_emojis(client: Client) -> Future>>; + fn get_emojis() -> Future>>; /// Bob accepts the verification request from Alice - fn accept_verification_request(client: Client) -> Future>; + fn accept_verification_request() -> Future>; /// Bob cancels the verification request from Alice /// alternative of terminate_verification - fn cancel_verification_request(client: Client) -> Future>; + fn cancel_verification_request() -> Future>; /// Bob accepts the verification request from Alice with specified method - fn accept_verification_request_with_method(client: Client, method: string) -> Future>; + fn accept_verification_request_with_method(method: string) -> Future>; /// Alice starts the SAS verification - fn start_sas_verification(client: Client) -> Future>; + fn start_sas_verification() -> Future>; /// Bob accepts the SAS verification - fn accept_sas_verification(client: Client) -> Future>; + fn accept_sas_verification() -> Future>; /// Bob cancels the SAS verification - fn cancel_sas_verification(client: Client) -> Future>; + fn cancel_sas_verification() -> Future>; /// Alice says to Bob that SAS verification matches and vice versa - fn confirm_sas_verification(client: Client) -> Future>; + fn confirm_sas_verification() -> Future>; /// Alice says to Bob that SAS verification doesn’t match and vice versa - fn mismatch_sas_verification(client: Client) -> Future>; + fn mismatch_sas_verification() -> Future>; +} + +object OptionVerificationEvent { + /// get data object + fn data() -> Option; } object VerificationEmoji { diff --git a/native/acter/src/api.rs b/native/acter/src/api.rs index c9a3ea5f2172..e574f422acd3 100644 --- a/native/acter/src/api.rs +++ b/native/acter/src/api.rs @@ -129,7 +129,9 @@ pub use tasks::{ }; pub use typing::TypingEvent; pub use utils::parse_markdown; -pub use verification::{SessionManager, VerificationEmoji, VerificationEvent}; +pub use verification::{ + OptionVerificationEvent, SessionManager, VerificationEmoji, VerificationEvent, +}; pub type DeviceId = matrix_sdk_base::ruma::OwnedDeviceId; pub type EventId = matrix_sdk_base::ruma::OwnedEventId; diff --git a/native/acter/src/api/verification.rs b/native/acter/src/api/verification.rs index 5f7e26f91e0a..fbe04577fa03 100644 --- a/native/acter/src/api/verification.rs +++ b/native/acter/src/api/verification.rs @@ -20,7 +20,7 @@ use matrix_sdk_base::ruma::{ room::message::{MessageType, OriginalSyncRoomMessageEvent}, AnyToDeviceEvent, EventContent, }, - OwnedDeviceId, OwnedUserId, UserId, + OwnedDeviceId, OwnedUserId, }; use std::{ collections::HashMap, @@ -34,11 +34,13 @@ use tracing::{error, info}; use super::{client::Client, common::DeviceRecord, RUNTIME}; -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct VerificationEvent { + client: SdkClient, + controller: VerificationController, event_type: String, flow_id: String, - sender: String, + sender: OwnedUserId, /// event content content: HashMap, /// emoji array @@ -46,11 +48,19 @@ pub struct VerificationEvent { } impl VerificationEvent { - pub(crate) fn new(event_type: String, flow_id: String, sender: OwnedUserId) -> Self { + pub(crate) fn new( + client: SdkClient, + controller: VerificationController, + event_type: String, + flow_id: String, + sender: OwnedUserId, + ) -> Self { VerificationEvent { + client, + controller, event_type, flow_id, - sender: sender.to_string(), + sender, content: Default::default(), emojis: Default::default(), } @@ -86,14 +96,13 @@ impl VerificationEvent { } // when other device triggered verification of this device, it can get emojis from remote server - pub async fn get_emojis(&self, client: Box) -> Result> { - let sender = UserId::parse(self.sender.clone())?; + pub async fn get_emojis(&self) -> Result> { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client - .core - .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -111,14 +120,13 @@ impl VerificationEvent { .await? } - pub async fn accept_verification_request(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn accept_verification_request(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client - .core - .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -137,14 +145,13 @@ impl VerificationEvent { } // alternative of terminate_verification - pub async fn cancel_verification_request(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn cancel_verification_request(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client - .core - .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -158,19 +165,14 @@ impl VerificationEvent { .await? } - pub async fn accept_verification_request_with_method( - &self, - client: Box, - method: String, - ) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn accept_verification_request_with_method(&self, method: String) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); let values = vec![VerificationMethod::from(method.as_str())]; RUNTIME .spawn(async move { let Some(request) = client - .core - .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -188,14 +190,13 @@ impl VerificationEvent { .await? } - pub async fn start_sas_verification(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn start_sas_verification(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(request) = client - .core - .client() .encryption() .get_verification_request(&sender, &flow_id) .await @@ -209,14 +210,13 @@ impl VerificationEvent { .await? } - pub async fn accept_sas_verification(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn accept_sas_verification(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client - .core - .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -235,14 +235,13 @@ impl VerificationEvent { .await? } - pub async fn cancel_sas_verification(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn cancel_sas_verification(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client - .core - .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -257,28 +256,23 @@ impl VerificationEvent { } #[cfg(feature = "testing")] - pub async fn send_verification_key(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn send_verification_key(&self) -> Result { + let client = self.client.clone(); RUNTIME .spawn(async move { - client - .core - .client() - .sync_once(SyncSettings::default()) - .await?; // send_outgoing_requests is called there + client.sync_once(SyncSettings::default()).await?; // send_outgoing_requests is called there Ok(true) }) .await? } - pub async fn confirm_sas_verification(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn confirm_sas_verification(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client - .core - .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -292,14 +286,13 @@ impl VerificationEvent { .await? } - pub async fn mismatch_sas_verification(&self, client: Box) -> Result { - let sender = UserId::parse(self.sender.clone())?; + pub async fn mismatch_sas_verification(&self) -> Result { + let client = self.client.clone(); + let sender = self.sender.clone(); let flow_id = self.flow_id.clone(); RUNTIME .spawn(async move { let Some(Verification::SasV1(sas)) = client - .core - .client() .encryption() .get_verification(&sender, &flow_id) .await @@ -314,6 +307,21 @@ impl VerificationEvent { } } +#[derive(Clone)] +pub struct OptionVerificationEvent { + data: Option, +} + +impl OptionVerificationEvent { + pub(crate) fn new(data: Option) -> Self { + OptionVerificationEvent { data } + } + + pub fn data(&self) -> Option { + self.data.clone() + } +} + #[derive(Clone, Debug)] pub struct VerificationEmoji { symbol: u32, @@ -352,7 +360,13 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Created".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); let methods = our_methods .iter() .map(|x| x.to_string()) @@ -370,7 +384,13 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Requested".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); let methods = their_methods .iter() .map(|x| x.to_string()) @@ -393,7 +413,13 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Ready".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); let methods = their_methods .iter() .map(|x| x.to_string()) @@ -419,7 +445,13 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Transitioned".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } @@ -429,17 +461,29 @@ async fn request_verification_handler( let device_id = client.device_id()?; let event_type = "VerificationRequestState::Done".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } - break; + break; // finish } VerificationRequestState::Cancelled(cancel_info) => { let device_id = client.device_id()?; let event_type = "VerificationRequestState::Cancelled".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); msg.set_content( "cancel_code".to_string(), cancel_info.cancel_code().to_string(), @@ -448,7 +492,7 @@ async fn request_verification_handler( if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } - break; + break; // finish } } } @@ -469,7 +513,13 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::KeysExchanged".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); if let Some(auth_string) = emojis { let sequence = auth_string .emojis @@ -497,7 +547,13 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Done".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); let devices = verified_devices .iter() .map(|x| x.device_id().to_string()) @@ -511,13 +567,19 @@ async fn sas_verification_handler( if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } - break; + break; // finish } SasState::Cancelled(cancel_info) => { let device_id = client.device_id()?; let event_type = "SasState::Cancelled".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); msg.set_content( "cancel_code".to_string(), cancel_info.cancel_code().to_string(), @@ -526,13 +588,19 @@ async fn sas_verification_handler( if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } - break; + break; // finish } SasState::Started { protocols } => { let device_id = client.device_id()?; let event_type = "SasState::Started".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); let key_agreement_protocols = protocols .key_agreement_protocols .iter() @@ -574,7 +642,13 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Accepted".to_string(); info!("{} got {}", device_id, event_type); - let mut msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let mut msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); msg.set_content( "key_agreement_protocol".to_string(), accepted_protocols.key_agreement_protocol.to_string(), @@ -594,7 +668,13 @@ async fn sas_verification_handler( let device_id = client.device_id()?; let event_type = "SasState::Confirmed".to_string(); info!("{} got {}", device_id, event_type); - let msg = VerificationEvent::new(event_type, flow_id.clone(), sender.clone()); + let msg = VerificationEvent::new( + client.core.client().clone(), + controller.clone(), + event_type, + flow_id.clone(), + sender.clone(), + ); if let Err(e) = controller.event_tx.send(msg) { error!("Dropping flow for {}: {}", flow_id, e); } @@ -630,13 +710,15 @@ impl VerificationController { let handle = client.add_event_handler( |ev: OriginalSyncRoomMessageEvent, c: SdkClient, - Ctx(mut me): Ctx| async move { + Ctx(me): Ctx| async move { if let MessageType::VerificationRequest(content) = &ev.content.msgtype { info!("MessageType::VerificationRequest"); let device_id = c.device_id().expect("DeviceId needed"); let event_type = ev.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), ev.event_id.to_string(), ev.sender, @@ -673,9 +755,7 @@ impl VerificationController { pub fn add_to_device_event_handler(&mut self, client: &SdkClient) { client.add_event_handler_context(self.clone()); let handle = client.add_event_handler( - |ev: AnyToDeviceEvent, - c: SdkClient, - Ctx(mut me): Ctx| async move { + |ev: AnyToDeviceEvent, c: SdkClient, Ctx(me): Ctx| async move { let device_id = c.device_id().expect("DeviceId needed"); match ev { AnyToDeviceEvent::KeyVerificationRequest(evt) => { @@ -683,14 +763,27 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); - msg.set_content("from_device".to_string(), evt.content.from_device.to_string()); - let methods = evt.content.methods.iter().map(|x| x.to_string()).collect::>(); + msg.set_content( + "from_device".to_string(), + evt.content.from_device.to_string(), + ); + let methods = evt + .content + .methods + .iter() + .map(|x| x.to_string()) + .collect::>(); msg.set_content("methods".to_string(), methods.join(",")); - msg.set_content("timestamp".to_string(), evt.content.timestamp.get().to_string()); + msg.set_content( + "timestamp".to_string(), + evt.content.timestamp.get().to_string(), + ); if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); } @@ -700,12 +793,22 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); - msg.set_content("from_device".to_string(), evt.content.from_device.to_string()); - let methods = evt.content.methods.iter().map(|x| x.to_string()).collect::>(); + msg.set_content( + "from_device".to_string(), + evt.content.from_device.to_string(), + ); + let methods = evt + .content + .methods + .iter() + .map(|x| x.to_string()) + .collect::>(); msg.set_content("methods".to_string(), methods.join(",")); if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); @@ -716,11 +819,16 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); - msg.set_content("from_device".to_string(), evt.content.from_device.to_string()); + msg.set_content( + "from_device".to_string(), + evt.content.from_device.to_string(), + ); match evt.content.method { StartMethod::SasV1(content) => { let key_agreement_protocols = content @@ -728,7 +836,10 @@ impl VerificationController { .iter() .map(|x| x.to_string()) .collect::>(); - msg.set_content("key_agreement_protocols".to_string(), key_agreement_protocols.join(",")); + msg.set_content( + "key_agreement_protocols".to_string(), + key_agreement_protocols.join(","), + ); let hashes = content .hashes .iter() @@ -740,13 +851,19 @@ impl VerificationController { .iter() .map(|x| x.to_string()) .collect::>(); - msg.set_content("message_authentication_codes".to_string(), message_authentication_codes.join(",")); + msg.set_content( + "message_authentication_codes".to_string(), + message_authentication_codes.join(","), + ); let short_authentication_string = content .short_authentication_string .iter() .map(|x| x.to_string()) .collect::>(); - msg.set_content("short_authentication_string".to_string(), short_authentication_string.join(",")); + msg.set_content( + "short_authentication_string".to_string(), + short_authentication_string.join(","), + ); } StartMethod::ReciprocateV1(content) => { let secret = match serde_json::to_string(&content.secret) { @@ -769,6 +886,8 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -783,21 +902,35 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, ); if let AcceptMethod::SasV1(content) = evt.content.method { msg.set_content("hash".to_string(), content.hash.to_string()); - msg.set_content("key_agreement_protocol".to_string(), content.key_agreement_protocol.to_string()); - msg.set_content("message_authentication_code".to_string(), content.message_authentication_code.to_string()); + msg.set_content( + "key_agreement_protocol".to_string(), + content.key_agreement_protocol.to_string(), + ); + msg.set_content( + "message_authentication_code".to_string(), + content.message_authentication_code.to_string(), + ); let short_authentication_string = content .short_authentication_string .iter() .map(|x| x.as_str().into()) .collect::>(); - msg.set_content("short_authentication_string".to_string(), short_authentication_string.join(",")); - msg.set_content("commitment".to_string(), content.commitment.to_string()); + msg.set_content( + "short_authentication_string".to_string(), + short_authentication_string.join(","), + ); + msg.set_content( + "commitment".to_string(), + content.commitment.to_string(), + ); } if let Err(e) = me.event_tx.send(msg) { error!("Dropping flow for {}: {}", evt.content.transaction_id, e); @@ -808,6 +941,8 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -823,6 +958,8 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let mut msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -845,6 +982,8 @@ impl VerificationController { let event_type = evt.content.event_type(); info!("{} got {}", device_id, event_type); let msg = VerificationEvent::new( + c, + me.clone(), event_type.to_string(), evt.content.transaction_id.to_string(), evt.sender, @@ -988,9 +1127,9 @@ impl SessionManager { } impl Client { - pub fn verification_event_rx(&self) -> impl Stream { + pub fn verification_event_rx(&self) -> impl Stream { BroadcastStream::new(self.verification_controller.event_rx.resubscribe()) - .map(|o| o.unwrap_or_default()) + .map(|o| OptionVerificationEvent::new(o.ok())) } pub fn session_manager(&self) -> SessionManager { @@ -1001,6 +1140,7 @@ impl Client { pub async fn request_verification(&self, dev_id: String) -> Result { let client = self.core.client().clone(); + let controller = self.verification_controller.clone(); let user_id = self.user_id()?; RUNTIME @@ -1020,6 +1160,8 @@ impl Client { let flow_id = request.flow_id().to_owned(); info!("requested verification - flow_id: {}", flow_id.clone()); let msg = VerificationEvent::new( + client, + controller, "VerificationRequestState::Created".to_owned(), flow_id, user_id, diff --git a/native/test/src/tests/verification.rs b/native/test/src/tests/verification.rs index b3b45632f42d..8bdb90127554 100644 --- a/native/test/src/tests/verification.rs +++ b/native/test/src/tests/verification.rs @@ -1,4 +1,4 @@ -use acter::api::VerificationEvent; +use acter::api::{OptionVerificationEvent, VerificationEvent}; use anyhow::Result; use futures::{ pin_mut, @@ -10,14 +10,16 @@ use tracing::info; use crate::utils::random_user; fn wait_for_verification_event( - rx: impl Stream, + rx: impl Stream, name: &str, ) -> VerificationEvent { pin_mut!(rx); loop { if let Some(event) = rx.next().now_or_never().flatten() { - if event.event_type() == name { - return event; + if let Some(data) = event.data() { + if data.event_type() == name { + return data; + } } } } @@ -86,10 +88,10 @@ async fn interactive_verification_started_from_request() -> Result<()> { // Bob accepts the request, sending a Ready request event - .accept_verification_request_with_method(Box::new(bob.clone()), "m.sas.v1".to_string()) + .accept_verification_request_with_method("m.sas.v1".to_string()) .await?; // And also immediately sends a start request - let started = event.start_sas_verification(Box::new(bob.clone())).await?; + let started = event.start_sas_verification().await?; assert!(started, "bob failed to start sas"); // ---------------------------------------------------------------------------- @@ -99,9 +101,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.ready"); // Alice immediately sends a start request - let started = event - .start_sas_verification(Box::new(alice.clone())) - .await?; + let started = event.start_sas_verification().await?; assert!(started, "alice failed to start sas verification"); // Now Alice receives the start event from Bob @@ -115,7 +115,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { let event = wait_for_verification_event(&mut bob_rx, "m.key.verification.start"); // Bob accepts it - let accepted = event.accept_sas_verification(Box::new(bob.clone())).await?; + let accepted = event.accept_sas_verification().await?; assert!(accepted, "bob failed to accept sas verification"); // ---------------------------------------------------------------------------- @@ -125,7 +125,7 @@ async fn interactive_verification_started_from_request() -> Result<()> { let event = wait_for_verification_event(&mut alice_rx, "m.key.verification.accept"); // Alice sends a key - event.send_verification_key(Box::new(alice.clone())).await?; + event.send_verification_key().await?; // ---------------------------------------------------------------------------- // On Bob’s device: @@ -134,13 +134,11 @@ async fn interactive_verification_started_from_request() -> Result<()> { let bob_event = wait_for_verification_event(&mut bob_rx, "m.key.verification.key"); // Bob gets the verification key from event - let emojis_from_alice = bob_event.get_emojis(Box::new(bob.clone())).await?; + let emojis_from_alice = bob_event.get_emojis().await?; info!("emojis from alice: {:?}", emojis_from_alice); // Bob sends a key - bob_event - .send_verification_key(Box::new(bob.clone())) - .await?; + bob_event.send_verification_key().await?; // ---------------------------------------------------------------------------- // On Alice’s device: @@ -149,22 +147,20 @@ async fn interactive_verification_started_from_request() -> Result<()> { let alice_event = wait_for_verification_event(&mut alice_rx, "m.key.verification.key"); // Alice gets the verification key from event - let emojis_from_bob = alice_event.get_emojis(Box::new(alice.clone())).await?; + let emojis_from_bob = alice_event.get_emojis().await?; info!("emojis from bob: {:?}", emojis_from_bob); // ---------------------------------------------------------------------------- // On Bob’s device: // Bob first confirms that the emojis match and sends the mac event... - bob_event.confirm_sas_verification(Box::new(bob)).await?; + bob_event.confirm_sas_verification().await?; // ---------------------------------------------------------------------------- // On Alice’s device: // Alice first confirms that the emojis match and sends the mac event... - alice_event - .confirm_sas_verification(Box::new(alice)) - .await?; + alice_event.confirm_sas_verification().await?; // ---------------------------------------------------------------------------- // On Bob’s device: diff --git a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart index f50d60feaf5a..3416c700b706 100644 --- a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart +++ b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart @@ -15954,7 +15954,7 @@ class Api { return tmp9; } - VerificationEvent? __clientVerificationEventRxStreamPoll( + OptionVerificationEvent? __clientVerificationEventRxStreamPoll( int boxed, int postCobject, int port, @@ -15984,9 +15984,9 @@ class Api { return null; } final ffi.Pointer tmp11_0 = ffi.Pointer.fromAddress(tmp11); - final tmp11_1 = _Box(this, tmp11_0, "drop_box_VerificationEvent"); + final tmp11_1 = _Box(this, tmp11_0, "drop_box_OptionVerificationEvent"); tmp11_1._finalizer = this._registerFinalizer(tmp11_1); - final tmp9 = VerificationEvent._(this, tmp11_1); + final tmp9 = OptionVerificationEvent._(this, tmp11_1); return tmp9; } @@ -28261,45 +28261,38 @@ class Api { ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_get_emojis"); late final _verificationEventGetEmojis = _verificationEventGetEmojisPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventAcceptVerificationRequestPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_accept_verification_request"); late final _verificationEventAcceptVerificationRequest = _verificationEventAcceptVerificationRequestPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventCancelVerificationRequestPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_cancel_verification_request"); late final _verificationEventCancelVerificationRequest = _verificationEventCancelVerificationRequestPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventAcceptVerificationRequestWithMethodPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( - ffi.IntPtr, ffi.IntPtr, ffi.IntPtr, ffi.UintPtr, @@ -28313,71 +28306,71 @@ class Api { int, int, int, - int, )>(); late final _verificationEventStartSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_start_sas_verification"); late final _verificationEventStartSasVerification = _verificationEventStartSasVerificationPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventAcceptSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_accept_sas_verification"); late final _verificationEventAcceptSasVerification = _verificationEventAcceptSasVerificationPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventCancelSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_cancel_sas_verification"); late final _verificationEventCancelSasVerification = _verificationEventCancelSasVerificationPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventConfirmSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_confirm_sas_verification"); late final _verificationEventConfirmSasVerification = _verificationEventConfirmSasVerificationPtr.asFunction< int Function( int, - int, )>(); late final _verificationEventMismatchSasVerificationPtr = _lookup< ffi.NativeFunction< ffi.IntPtr Function( ffi.IntPtr, - ffi.IntPtr, )>>("__VerificationEvent_mismatch_sas_verification"); late final _verificationEventMismatchSasVerification = _verificationEventMismatchSasVerificationPtr.asFunction< int Function( int, + )>(); + late final _optionVerificationEventDataPtr = _lookup< + ffi.NativeFunction< + _OptionVerificationEventDataReturn Function( + ffi.IntPtr, + )>>("__OptionVerificationEvent_data"); + + late final _optionVerificationEventData = + _optionVerificationEventDataPtr.asFunction< + _OptionVerificationEventDataReturn Function( int, )>(); late final _verificationEmojiSymbolPtr = _lookup< @@ -55261,7 +55254,7 @@ class Client { } /// Get the verification event receiver - Stream verificationEventRx() { + Stream verificationEventRx() { var tmp0 = 0; tmp0 = _box.borrow(); final tmp1 = _api._clientVerificationEventRx( @@ -57922,227 +57915,205 @@ class VerificationEvent { } /// Get emoji array - Future getEmojis( - Client client, - ) { - final tmp1 = client; + Future getEmojis() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventGetEmojis( + final tmp1 = _api._verificationEventGetEmojis( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = - _Box(_api, tmp5_0, "__VerificationEvent_get_emojis_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = - _nativeFuture(tmp5_1, _api.__verificationEventGetEmojisFuturePoll); - return tmp4; + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = + _Box(_api, tmp3_0, "__VerificationEvent_get_emojis_future_drop"); + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = + _nativeFuture(tmp3_1, _api.__verificationEventGetEmojisFuturePoll); + return tmp2; } /// Bob accepts the verification request from Alice - Future acceptVerificationRequest( - Client client, - ) { - final tmp1 = client; + Future acceptVerificationRequest() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventAcceptVerificationRequest( + final tmp1 = _api._verificationEventAcceptVerificationRequest( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_accept_verification_request_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventAcceptVerificationRequestFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventAcceptVerificationRequestFuturePoll); + return tmp2; } /// Bob cancels the verification request from Alice /// alternative of terminate_verification - Future cancelVerificationRequest( - Client client, - ) { - final tmp1 = client; + Future cancelVerificationRequest() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventCancelVerificationRequest( + final tmp1 = _api._verificationEventCancelVerificationRequest( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_cancel_verification_request_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventCancelVerificationRequestFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventCancelVerificationRequestFuturePoll); + return tmp2; } /// Bob accepts the verification request from Alice with specified method Future acceptVerificationRequestWithMethod( - Client client, String method, ) { - final tmp1 = client; - final tmp3 = method; + final tmp1 = method; var tmp0 = 0; var tmp2 = 0; + var tmp3 = 0; var tmp4 = 0; - var tmp5 = 0; - var tmp6 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3_0 = utf8.encode(tmp3); - tmp5 = tmp3_0.length; + final tmp1_0 = utf8.encode(tmp1); + tmp3 = tmp1_0.length; - final ffi.Pointer tmp4_0 = _api.__allocate(tmp5 * 1, 1); - final Uint8List tmp4_1 = tmp4_0.asTypedList(tmp5); - tmp4_1.setAll(0, tmp3_0); - tmp4 = tmp4_0.address; - tmp6 = tmp5; - final tmp7 = _api._verificationEventAcceptVerificationRequestWithMethod( + final ffi.Pointer tmp2_0 = _api.__allocate(tmp3 * 1, 1); + final Uint8List tmp2_1 = tmp2_0.asTypedList(tmp3); + tmp2_1.setAll(0, tmp1_0); + tmp2 = tmp2_0.address; + tmp4 = tmp3; + final tmp5 = _api._verificationEventAcceptVerificationRequestWithMethod( tmp0, tmp2, + tmp3, tmp4, - tmp5, - tmp6, ); - final tmp9 = tmp7; - final ffi.Pointer tmp9_0 = ffi.Pointer.fromAddress(tmp9); - final tmp9_1 = _Box(_api, tmp9_0, + final tmp7 = tmp5; + final ffi.Pointer tmp7_0 = ffi.Pointer.fromAddress(tmp7); + final tmp7_1 = _Box(_api, tmp7_0, "__VerificationEvent_accept_verification_request_with_method_future_drop"); - tmp9_1._finalizer = _api._registerFinalizer(tmp9_1); - final tmp8 = _nativeFuture(tmp9_1, + tmp7_1._finalizer = _api._registerFinalizer(tmp7_1); + final tmp6 = _nativeFuture(tmp7_1, _api.__verificationEventAcceptVerificationRequestWithMethodFuturePoll); - return tmp8; + return tmp6; } /// Alice starts the SAS verification - Future startSasVerification( - Client client, - ) { - final tmp1 = client; + Future startSasVerification() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventStartSasVerification( + final tmp1 = _api._verificationEventStartSasVerification( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box( - _api, tmp5_0, "__VerificationEvent_start_sas_verification_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventStartSasVerificationFuturePoll); - return tmp4; + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box( + _api, tmp3_0, "__VerificationEvent_start_sas_verification_future_drop"); + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventStartSasVerificationFuturePoll); + return tmp2; } /// Bob accepts the SAS verification - Future acceptSasVerification( - Client client, - ) { - final tmp1 = client; + Future acceptSasVerification() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventAcceptSasVerification( + final tmp1 = _api._verificationEventAcceptSasVerification( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_accept_sas_verification_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventAcceptSasVerificationFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventAcceptSasVerificationFuturePoll); + return tmp2; } /// Bob cancels the SAS verification - Future cancelSasVerification( - Client client, - ) { - final tmp1 = client; + Future cancelSasVerification() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventCancelSasVerification( + final tmp1 = _api._verificationEventCancelSasVerification( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_cancel_sas_verification_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventCancelSasVerificationFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventCancelSasVerificationFuturePoll); + return tmp2; } /// Alice says to Bob that SAS verification matches and vice versa - Future confirmSasVerification( - Client client, - ) { - final tmp1 = client; + Future confirmSasVerification() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventConfirmSasVerification( + final tmp1 = _api._verificationEventConfirmSasVerification( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_confirm_sas_verification_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventConfirmSasVerificationFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventConfirmSasVerificationFuturePoll); + return tmp2; } /// Alice says to Bob that SAS verification doesn’t match and vice versa - Future mismatchSasVerification( - Client client, - ) { - final tmp1 = client; + Future mismatchSasVerification() { var tmp0 = 0; - var tmp2 = 0; tmp0 = _box.borrow(); - tmp2 = tmp1._box.move(); - final tmp3 = _api._verificationEventMismatchSasVerification( + final tmp1 = _api._verificationEventMismatchSasVerification( tmp0, - tmp2, ); - final tmp5 = tmp3; - final ffi.Pointer tmp5_0 = ffi.Pointer.fromAddress(tmp5); - final tmp5_1 = _Box(_api, tmp5_0, + final tmp3 = tmp1; + final ffi.Pointer tmp3_0 = ffi.Pointer.fromAddress(tmp3); + final tmp3_1 = _Box(_api, tmp3_0, "__VerificationEvent_mismatch_sas_verification_future_drop"); - tmp5_1._finalizer = _api._registerFinalizer(tmp5_1); - final tmp4 = _nativeFuture( - tmp5_1, _api.__verificationEventMismatchSasVerificationFuturePoll); - return tmp4; + tmp3_1._finalizer = _api._registerFinalizer(tmp3_1); + final tmp2 = _nativeFuture( + tmp3_1, _api.__verificationEventMismatchSasVerificationFuturePoll); + return tmp2; + } + + /// Manually drops the object and unregisters the FinalizableHandle. + void drop() { + _box.drop(); + } +} + +class OptionVerificationEvent { + final Api _api; + final _Box _box; + + OptionVerificationEvent._(this._api, this._box); + + /// get data object + VerificationEvent? data() { + var tmp0 = 0; + tmp0 = _box.borrow(); + final tmp1 = _api._optionVerificationEventData( + tmp0, + ); + final tmp3 = tmp1.arg0; + final tmp4 = tmp1.arg1; + if (tmp3 == 0) { + return null; + } + final ffi.Pointer tmp4_0 = ffi.Pointer.fromAddress(tmp4); + final tmp4_1 = _Box(_api, tmp4_0, "drop_box_VerificationEvent"); + tmp4_1._finalizer = _api._registerFinalizer(tmp4_1); + final tmp2 = VerificationEvent._(_api, tmp4_1); + return tmp2; } /// Manually drops the object and unregisters the FinalizableHandle. @@ -61656,6 +61627,13 @@ class _VerificationEventGetContentReturn extends ffi.Struct { external int arg3; } +class _OptionVerificationEventDataReturn extends ffi.Struct { + @ffi.Uint8() + external int arg0; + @ffi.IntPtr() + external int arg1; +} + class _VerificationEmojiDescriptionReturn extends ffi.Struct { @ffi.IntPtr() external int arg0; From 8ff8191aad386d987fffd4a938a9d636fe9efbcc Mon Sep 17 00:00:00 2001 From: bitfriend Date: Thu, 12 Dec 2024 02:33:40 +0800 Subject: [PATCH 07/10] Use filter_map() to remove Option from VerificationEvent --- .../notifiers/verification_notifiers.dart | 13 +---- native/acter/api.rsh | 7 +-- native/acter/src/api.rs | 4 +- native/acter/src/api/verification.rs | 24 ++------ native/test/src/tests/verification.rs | 10 ++-- .../rust_sdk/lib/acter_flutter_sdk_ffi.dart | 57 ++----------------- 6 files changed, 19 insertions(+), 96 deletions(-) diff --git a/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart b/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart index a280e7c69fd0..d4d1bab9a973 100644 --- a/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart +++ b/app/lib/features/cross_signing/providers/notifiers/verification_notifiers.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:acter/common/extensions/options.dart'; import 'package:acter_flutter_sdk/acter_flutter_sdk_ffi.dart'; import 'package:logging/logging.dart'; import 'package:riverpod/riverpod.dart'; @@ -18,8 +17,8 @@ class VerificationNotifier extends StateNotifier { final Ref ref; final Client client; - late Stream? _listener; - late StreamSubscription? _poller; + late Stream? _listener; + late StreamSubscription? _poller; VerificationNotifier({ required this.ref, @@ -31,13 +30,7 @@ class VerificationNotifier extends StateNotifier { void _init() { _listener = client.verificationEventRx(); // keep it resident in memory _poller = _listener?.listen( - (event) { - final data = event.data(); - data.map( - (event) => _handleEvent(event), - orElse: () => _log.info('invalid verification event'), - ); - }, + _handleEvent, onError: (e, s) { _log.severe('stream errored', e, s); }, diff --git a/native/acter/api.rsh b/native/acter/api.rsh index 07294b159d4a..8363c3363228 100644 --- a/native/acter/api.rsh +++ b/native/acter/api.rsh @@ -2803,7 +2803,7 @@ object Client { fn logout() -> Future>; /// Get the verification event receiver - fn verification_event_rx() -> Stream; + fn verification_event_rx() -> Stream; /// Get session manager that returns all/verified/unverified/inactive session list fn session_manager() -> SessionManager; @@ -3136,11 +3136,6 @@ object VerificationEvent { fn mismatch_sas_verification() -> Future>; } -object OptionVerificationEvent { - /// get data object - fn data() -> Option; -} - object VerificationEmoji { /// binary representation of emoji unicode fn symbol() -> u32; diff --git a/native/acter/src/api.rs b/native/acter/src/api.rs index e574f422acd3..c9a3ea5f2172 100644 --- a/native/acter/src/api.rs +++ b/native/acter/src/api.rs @@ -129,9 +129,7 @@ pub use tasks::{ }; pub use typing::TypingEvent; pub use utils::parse_markdown; -pub use verification::{ - OptionVerificationEvent, SessionManager, VerificationEmoji, VerificationEvent, -}; +pub use verification::{SessionManager, VerificationEmoji, VerificationEvent}; pub type DeviceId = matrix_sdk_base::ruma::OwnedDeviceId; pub type EventId = matrix_sdk_base::ruma::OwnedEventId; diff --git a/native/acter/src/api/verification.rs b/native/acter/src/api/verification.rs index fbe04577fa03..e82e29fbe7d5 100644 --- a/native/acter/src/api/verification.rs +++ b/native/acter/src/api/verification.rs @@ -24,6 +24,7 @@ use matrix_sdk_base::ruma::{ }; use std::{ collections::HashMap, + marker::Unpin, ops::Deref, sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, @@ -307,21 +308,6 @@ impl VerificationEvent { } } -#[derive(Clone)] -pub struct OptionVerificationEvent { - data: Option, -} - -impl OptionVerificationEvent { - pub(crate) fn new(data: Option) -> Self { - OptionVerificationEvent { data } - } - - pub fn data(&self) -> Option { - self.data.clone() - } -} - #[derive(Clone, Debug)] pub struct VerificationEmoji { symbol: u32, @@ -1127,9 +1113,11 @@ impl SessionManager { } impl Client { - pub fn verification_event_rx(&self) -> impl Stream { - BroadcastStream::new(self.verification_controller.event_rx.resubscribe()) - .map(|o| OptionVerificationEvent::new(o.ok())) + // this return value should be able to unpin, because wait_for_verification_event calls pin_mut internally + // this return value should be wrapped in Box::pin, to make unpin possible + pub fn verification_event_rx(&self) -> impl Stream + Unpin { + let mut stream = BroadcastStream::new(self.verification_controller.event_rx.resubscribe()); + Box::pin(stream.filter_map(|o| async move { o.ok() })) } pub fn session_manager(&self) -> SessionManager { diff --git a/native/test/src/tests/verification.rs b/native/test/src/tests/verification.rs index 8bdb90127554..037be58863d1 100644 --- a/native/test/src/tests/verification.rs +++ b/native/test/src/tests/verification.rs @@ -1,4 +1,4 @@ -use acter::api::{OptionVerificationEvent, VerificationEvent}; +use acter::api::VerificationEvent; use anyhow::Result; use futures::{ pin_mut, @@ -10,16 +10,14 @@ use tracing::info; use crate::utils::random_user; fn wait_for_verification_event( - rx: impl Stream, + rx: impl Stream, name: &str, ) -> VerificationEvent { pin_mut!(rx); loop { if let Some(event) = rx.next().now_or_never().flatten() { - if let Some(data) = event.data() { - if data.event_type() == name { - return data; - } + if event.event_type() == name { + return event; } } } diff --git a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart index 3416c700b706..f34d91ca8002 100644 --- a/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart +++ b/packages/rust_sdk/lib/acter_flutter_sdk_ffi.dart @@ -15954,7 +15954,7 @@ class Api { return tmp9; } - OptionVerificationEvent? __clientVerificationEventRxStreamPoll( + VerificationEvent? __clientVerificationEventRxStreamPoll( int boxed, int postCobject, int port, @@ -15984,9 +15984,9 @@ class Api { return null; } final ffi.Pointer tmp11_0 = ffi.Pointer.fromAddress(tmp11); - final tmp11_1 = _Box(this, tmp11_0, "drop_box_OptionVerificationEvent"); + final tmp11_1 = _Box(this, tmp11_0, "drop_box_VerificationEvent"); tmp11_1._finalizer = this._registerFinalizer(tmp11_1); - final tmp9 = OptionVerificationEvent._(this, tmp11_1); + final tmp9 = VerificationEvent._(this, tmp11_1); return tmp9; } @@ -28362,17 +28362,6 @@ class Api { int Function( int, )>(); - late final _optionVerificationEventDataPtr = _lookup< - ffi.NativeFunction< - _OptionVerificationEventDataReturn Function( - ffi.IntPtr, - )>>("__OptionVerificationEvent_data"); - - late final _optionVerificationEventData = - _optionVerificationEventDataPtr.asFunction< - _OptionVerificationEventDataReturn Function( - int, - )>(); late final _verificationEmojiSymbolPtr = _lookup< ffi.NativeFunction< ffi.Uint32 Function( @@ -55254,7 +55243,7 @@ class Client { } /// Get the verification event receiver - Stream verificationEventRx() { + Stream verificationEventRx() { var tmp0 = 0; tmp0 = _box.borrow(); final tmp1 = _api._clientVerificationEventRx( @@ -58091,37 +58080,6 @@ class VerificationEvent { } } -class OptionVerificationEvent { - final Api _api; - final _Box _box; - - OptionVerificationEvent._(this._api, this._box); - - /// get data object - VerificationEvent? data() { - var tmp0 = 0; - tmp0 = _box.borrow(); - final tmp1 = _api._optionVerificationEventData( - tmp0, - ); - final tmp3 = tmp1.arg0; - final tmp4 = tmp1.arg1; - if (tmp3 == 0) { - return null; - } - final ffi.Pointer tmp4_0 = ffi.Pointer.fromAddress(tmp4); - final tmp4_1 = _Box(_api, tmp4_0, "drop_box_VerificationEvent"); - tmp4_1._finalizer = _api._registerFinalizer(tmp4_1); - final tmp2 = VerificationEvent._(_api, tmp4_1); - return tmp2; - } - - /// Manually drops the object and unregisters the FinalizableHandle. - void drop() { - _box.drop(); - } -} - class VerificationEmoji { final Api _api; final _Box _box; @@ -61627,13 +61585,6 @@ class _VerificationEventGetContentReturn extends ffi.Struct { external int arg3; } -class _OptionVerificationEventDataReturn extends ffi.Struct { - @ffi.Uint8() - external int arg0; - @ffi.IntPtr() - external int arg1; -} - class _VerificationEmojiDescriptionReturn extends ffi.Struct { @ffi.IntPtr() external int arg0; From fa2151caeb803c982f9fca321d6847123e2fa0bb Mon Sep 17 00:00:00 2001 From: bitfriend Date: Thu, 12 Dec 2024 14:03:17 +0800 Subject: [PATCH 08/10] Update description --- native/acter/src/api/verification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/acter/src/api/verification.rs b/native/acter/src/api/verification.rs index e82e29fbe7d5..ca1ecf7b2031 100644 --- a/native/acter/src/api/verification.rs +++ b/native/acter/src/api/verification.rs @@ -1113,7 +1113,7 @@ impl SessionManager { } impl Client { - // this return value should be able to unpin, because wait_for_verification_event calls pin_mut internally + // this return value should be unpinned when wait_for_verification_event ends, because it calls pin_mut // this return value should be wrapped in Box::pin, to make unpin possible pub fn verification_event_rx(&self) -> impl Stream + Unpin { let mut stream = BroadcastStream::new(self.verification_controller.event_rx.resubscribe()); From 65f1e301d3f52063f81cebb6fa60450eade7ebcc Mon Sep 17 00:00:00 2001 From: bitfriend Date: Sat, 14 Dec 2024 02:05:35 +0800 Subject: [PATCH 09/10] Use filter_map() to avoid invalid DeviceEvent --- native/acter/src/api/device.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/native/acter/src/api/device.rs b/native/acter/src/api/device.rs index 43afd746e18c..594717a54d6d 100644 --- a/native/acter/src/api/device.rs +++ b/native/acter/src/api/device.rs @@ -6,6 +6,7 @@ use futures::{ use matrix_sdk::{executor::JoinHandle, Client as SdkClient}; use matrix_sdk_base::ruma::{OwnedDeviceId, OwnedUserId}; use std::{ + marker::Unpin, sync::Arc, time::{Duration, SystemTime, UNIX_EPOCH}, }; @@ -105,9 +106,9 @@ impl DeviceController { } impl Client { - pub fn device_event_rx(&self) -> impl Stream { - BroadcastStream::new(self.device_controller.event_rx.resubscribe()) - .map(|o| o.unwrap_or_default()) + pub fn device_event_rx(&self) -> impl Stream + Unpin { + let mut stream = BroadcastStream::new(self.device_controller.event_rx.resubscribe()); + Box::pin(stream.filter_map(|o| async move { o.ok() })) } pub async fn device_records(&self, verified: bool) -> Result> { From 0c79d2f408e75720ec425355d20c17f07aa28cda Mon Sep 17 00:00:00 2001 From: bitfriend Date: Sat, 14 Dec 2024 02:05:48 +0800 Subject: [PATCH 10/10] Update description --- native/acter/src/api/device.rs | 2 ++ native/acter/src/api/verification.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/native/acter/src/api/device.rs b/native/acter/src/api/device.rs index 594717a54d6d..65b4d271e9ba 100644 --- a/native/acter/src/api/device.rs +++ b/native/acter/src/api/device.rs @@ -106,6 +106,8 @@ impl DeviceController { } impl Client { + // this return value should be Unpin, because next() of this stream is called in interactive_verification_started_from_request + // this return value should be wrapped in Box::pin, to make unpin possible pub fn device_event_rx(&self) -> impl Stream + Unpin { let mut stream = BroadcastStream::new(self.device_controller.event_rx.resubscribe()); Box::pin(stream.filter_map(|o| async move { o.ok() })) diff --git a/native/acter/src/api/verification.rs b/native/acter/src/api/verification.rs index ca1ecf7b2031..c88381a6200e 100644 --- a/native/acter/src/api/verification.rs +++ b/native/acter/src/api/verification.rs @@ -1113,7 +1113,7 @@ impl SessionManager { } impl Client { - // this return value should be unpinned when wait_for_verification_event ends, because it calls pin_mut + // this return value should be Unpin, because next() of this stream is called in wait_for_verification_event // this return value should be wrapped in Box::pin, to make unpin possible pub fn verification_event_rx(&self) -> impl Stream + Unpin { let mut stream = BroadcastStream::new(self.verification_controller.event_rx.resubscribe());