@@ -4,15 +4,16 @@ use base64::{decode_config, encode_config, STANDARD_NO_PAD};
44use futures_util:: { Stream , StreamExt } ;
55use matrix_sdk_crypto:: {
66 matrix_sdk_qrcode:: QrVerificationData , CancelInfo as RustCancelInfo , QrVerification as InnerQr ,
7- Sas as InnerSas , SasState as RustSasState , Verification as InnerVerification ,
8- VerificationRequest as InnerVerificationRequest ,
7+ QrVerificationState , Sas as InnerSas , SasState as RustSasState ,
8+ Verification as InnerVerification , VerificationRequest as InnerVerificationRequest ,
9+ VerificationRequestState as RustVerificationRequestState ,
910} ;
1011use ruma:: events:: key:: verification:: VerificationMethod ;
1112use tokio:: runtime:: Handle ;
1213
1314use crate :: { CryptoStoreError , OutgoingVerificationRequest , SignatureUploadRequest } ;
1415
15- /// Callback that will be passed over the FFI to report changes to a SAS
16+ /// Listener that will be passed over the FFI to report changes to a SAS
1617/// verification.
1718pub trait SasListener : Send {
1819 /// The callback that should be called on the Rust side
@@ -23,15 +24,6 @@ pub trait SasListener: Send {
2324 fn on_change ( & self , state : SasState ) ;
2425}
2526
26- impl < T : Fn ( SasState ) > SasListener for T
27- where
28- T : Send ,
29- {
30- fn on_change ( & self , state : SasState ) {
31- self ( state)
32- }
33- }
34-
3527/// An Enum describing the state the SAS verification is in.
3628pub enum SasState {
3729 /// The verification has been started, the protocols that should be used
@@ -98,7 +90,7 @@ impl Verification {
9890 /// returns `None` if the verification is not a `QrCode` verification.
9991 pub fn as_qr ( & self ) -> Option < Arc < QrCode > > {
10092 if let InnerVerification :: QrV1 ( qr) = & self . inner {
101- Some ( QrCode { inner : qr. to_owned ( ) } . into ( ) )
93+ Some ( QrCode { inner : qr. to_owned ( ) , runtime : self . runtime . to_owned ( ) } . into ( ) )
10294 } else {
10395 None
10496 }
@@ -239,20 +231,20 @@ impl Sas {
239231 /// │ Done │
240232 /// └───────┘
241233 /// ```
242- pub fn set_changes_listener ( & self , callback : Box < dyn SasListener > ) {
234+ pub fn set_changes_listener ( & self , listener : Box < dyn SasListener > ) {
243235 let stream = self . inner . changes ( ) ;
244236
245- self . runtime . spawn ( Self :: changes_callback ( stream, callback ) ) ;
237+ self . runtime . spawn ( Self :: changes_listener ( stream, listener ) ) ;
246238 }
247239
248240 /// Get the current state of the SAS verification process.
249241 pub fn state ( & self ) -> SasState {
250242 self . inner . state ( ) . into ( )
251243 }
252244
253- async fn changes_callback (
245+ async fn changes_listener (
254246 mut stream : impl Stream < Item = RustSasState > + std:: marker:: Unpin ,
255- callback : Box < dyn SasListener > ,
247+ listener : Box < dyn SasListener > ,
256248 ) {
257249 while let Some ( state) = stream. next ( ) . await {
258250 // If we receive a done or a cancelled state we're at the end of our road, we
@@ -261,7 +253,7 @@ impl Sas {
261253 let should_break =
262254 matches ! ( state, RustSasState :: Done { .. } | RustSasState :: Cancelled { .. } ) ;
263255
264- callback . on_change ( state. into ( ) ) ;
256+ listener . on_change ( state. into ( ) ) ;
265257
266258 if should_break {
267259 break ;
@@ -270,10 +262,55 @@ impl Sas {
270262 }
271263}
272264
265+ /// Listener that will be passed over the FFI to report changes to a QrCode
266+ /// verification.
267+ pub trait QrCodeListener : Send {
268+ /// The callback that should be called on the Rust side
269+ ///
270+ /// # Arguments
271+ ///
272+ /// * `state` - The current state of the QrCode verification.
273+ fn on_change ( & self , state : QrCodeState ) ;
274+ }
275+
276+ /// An Enum describing the state the QrCode verification is in.
277+ pub enum QrCodeState {
278+ /// The QR verification has been started.
279+ Started ,
280+ /// The QR verification has been scanned by the other side.
281+ Scanned ,
282+ /// The scanning of the QR code has been confirmed by us.
283+ Confirmed ,
284+ /// We have successfully scanned the QR code and are able to send a
285+ /// reciprocation event.
286+ Reciprocated ,
287+ /// The verification process has been successfully concluded.
288+ Done ,
289+ /// The verification process has been cancelled.
290+ Cancelled {
291+ /// Information about the reason of the cancellation.
292+ cancel_info : CancelInfo ,
293+ } ,
294+ }
295+
296+ impl From < QrVerificationState > for QrCodeState {
297+ fn from ( value : QrVerificationState ) -> Self {
298+ match value {
299+ QrVerificationState :: Started => Self :: Started ,
300+ QrVerificationState :: Scanned => Self :: Scanned ,
301+ QrVerificationState :: Confirmed => Self :: Confirmed ,
302+ QrVerificationState :: Reciprocated => Self :: Reciprocated ,
303+ QrVerificationState :: Done { .. } => Self :: Done ,
304+ QrVerificationState :: Cancelled ( c) => Self :: Cancelled { cancel_info : c. into ( ) } ,
305+ }
306+ }
307+ }
308+
273309/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
274310/// verification flow.
275311pub struct QrCode {
276312 pub ( crate ) inner : InnerQr ,
313+ pub ( crate ) runtime : Handle ,
277314}
278315
279316impl QrCode {
@@ -366,6 +403,41 @@ impl QrCode {
366403 pub fn generate_qr_code ( & self ) -> Option < String > {
367404 self . inner . to_bytes ( ) . map ( |data| encode_config ( data, STANDARD_NO_PAD ) ) . ok ( )
368405 }
406+
407+ /// Set a listener for changes in the QrCode verification process.
408+ ///
409+ /// The given callback will be called whenever the state changes.
410+ pub fn set_changes_listener ( & self , listener : Box < dyn QrCodeListener > ) {
411+ let stream = self . inner . changes ( ) ;
412+
413+ self . runtime . spawn ( Self :: changes_listener ( stream, listener) ) ;
414+ }
415+
416+ /// Get the current state of the QrCode verification process.
417+ pub fn state ( & self ) -> QrCodeState {
418+ self . inner . state ( ) . into ( )
419+ }
420+
421+ async fn changes_listener (
422+ mut stream : impl Stream < Item = QrVerificationState > + std:: marker:: Unpin ,
423+ listener : Box < dyn QrCodeListener > ,
424+ ) {
425+ while let Some ( state) = stream. next ( ) . await {
426+ // If we receive a done or a cancelled state we're at the end of our road, we
427+ // break out of the loop to deallocate the stream and finish the
428+ // task.
429+ let should_break = matches ! (
430+ state,
431+ QrVerificationState :: Done { .. } | QrVerificationState :: Cancelled { .. }
432+ ) ;
433+
434+ listener. on_change ( state. into ( ) ) ;
435+
436+ if should_break {
437+ break ;
438+ }
439+ }
440+ }
369441}
370442
371443/// Information on why a verification flow has been cancelled and by whom.
@@ -425,6 +497,58 @@ pub struct ConfirmVerificationResult {
425497 pub signature_request : Option < SignatureUploadRequest > ,
426498}
427499
500+ /// Listener that will be passed over the FFI to report changes to a
501+ /// verification request.
502+ pub trait VerificationRequestListener : Send {
503+ /// The callback that should be called on the Rust side
504+ ///
505+ /// # Arguments
506+ ///
507+ /// * `state` - The current state of the verification request.
508+ fn on_change ( & self , state : VerificationRequestState ) ;
509+ }
510+
511+ /// An Enum describing the state the QrCode verification is in.
512+ pub enum VerificationRequestState {
513+ /// The verification request was sent
514+ Requested ,
515+ /// The verification request is ready to start a verification flow.
516+ Ready {
517+ /// The verification methods supported by the other side.
518+ their_methods : Vec < String > ,
519+
520+ /// The verification methods supported by the us.
521+ our_methods : Vec < String > ,
522+ } ,
523+ /// The verification flow that was started with this request has finished.
524+ Done ,
525+ /// The verification process has been cancelled.
526+ Cancelled {
527+ /// Information about the reason of the cancellation.
528+ cancel_info : CancelInfo ,
529+ } ,
530+ }
531+
532+ impl From < RustVerificationRequestState > for VerificationRequestState {
533+ fn from ( value : RustVerificationRequestState ) -> Self {
534+ match value {
535+ // The clients do not need to distinguish `Created` and `Requested` state
536+ RustVerificationRequestState :: Created { .. } => Self :: Requested ,
537+ RustVerificationRequestState :: Requested { .. } => Self :: Requested ,
538+ RustVerificationRequestState :: Ready {
539+ their_methods,
540+ our_methods,
541+ other_device_id : _,
542+ } => Self :: Ready {
543+ their_methods : their_methods. iter ( ) . map ( |m| m. to_string ( ) ) . collect ( ) ,
544+ our_methods : our_methods. iter ( ) . map ( |m| m. to_string ( ) ) . collect ( ) ,
545+ } ,
546+ RustVerificationRequestState :: Done => Self :: Done ,
547+ RustVerificationRequestState :: Cancelled ( c) => Self :: Cancelled { cancel_info : c. into ( ) } ,
548+ }
549+ }
550+ }
551+
428552/// The verificatoin request object which then can transition into some concrete
429553/// verification method
430554pub struct VerificationRequest {
@@ -559,7 +683,7 @@ impl VerificationRequest {
559683 Ok ( self
560684 . runtime
561685 . block_on ( self . inner . generate_qr_code ( ) ) ?
562- . map ( |qr| QrCode { inner : qr } . into ( ) ) )
686+ . map ( |qr| QrCode { inner : qr, runtime : self . runtime . clone ( ) } . into ( ) ) )
563687 }
564688
565689 /// Pass data from a scanned QR code to an active verification request and
@@ -585,9 +709,48 @@ impl VerificationRequest {
585709 if let Some ( qr) = self . runtime . block_on ( self . inner . scan_qr_code ( data) ) . ok ( ) ? {
586710 let request = qr. reciprocate ( ) ?;
587711
588- Some ( ScanResult { qr : QrCode { inner : qr } . into ( ) , request : request. into ( ) } )
712+ Some ( ScanResult {
713+ qr : QrCode { inner : qr, runtime : self . runtime . clone ( ) } . into ( ) ,
714+ request : request. into ( ) ,
715+ } )
589716 } else {
590717 None
591718 }
592719 }
720+
721+ /// Set a listener for changes in the verification request
722+ ///
723+ /// The given callback will be called whenever the state changes.
724+ pub fn set_changes_listener ( & self , listener : Box < dyn VerificationRequestListener > ) {
725+ let stream = self . inner . changes ( ) ;
726+
727+ self . runtime . spawn ( Self :: changes_listener ( stream, listener) ) ;
728+ }
729+
730+ /// Get the current state of the verification request.
731+ pub fn state ( & self ) -> VerificationRequestState {
732+ self . inner . state ( ) . into ( )
733+ }
734+
735+ async fn changes_listener (
736+ mut stream : impl Stream < Item = RustVerificationRequestState > + std:: marker:: Unpin ,
737+ listener : Box < dyn VerificationRequestListener > ,
738+ ) {
739+ while let Some ( state) = stream. next ( ) . await {
740+ // If we receive a done or a cancelled state we're at the end of our road, we
741+ // break out of the loop to deallocate the stream and finish the
742+ // task.
743+ let should_break = matches ! (
744+ state,
745+ RustVerificationRequestState :: Done { .. }
746+ | RustVerificationRequestState :: Cancelled { .. }
747+ ) ;
748+
749+ listener. on_change ( state. into ( ) ) ;
750+
751+ if should_break {
752+ break ;
753+ }
754+ }
755+ }
593756}
0 commit comments