From 80a30bcdd6de8972b7cefb9712c979cb6fb07418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Fri, 25 Jun 2021 17:55:39 +0200 Subject: [PATCH] crypto: Add all the common accessors to the qr code verification --- matrix_sdk_crypto/src/verification/qrcode.rs | 109 ++++++++++++++---- .../src/verification/requests.rs | 15 ++- 2 files changed, 97 insertions(+), 27 deletions(-) diff --git a/matrix_sdk_crypto/src/verification/qrcode.rs b/matrix_sdk_crypto/src/verification/qrcode.rs index e57e88fe..0b414b80 100644 --- a/matrix_sdk_crypto/src/verification/qrcode.rs +++ b/matrix_sdk_crypto/src/verification/qrcode.rs @@ -33,7 +33,7 @@ use ruma::{ }, AnyMessageEventContent, AnyToDeviceEventContent, }, - DeviceIdBox, DeviceKeyAlgorithm, UserId, + DeviceId, DeviceIdBox, DeviceKeyAlgorithm, RoomId, UserId, }; use thiserror::Error; @@ -83,6 +83,7 @@ pub struct QrVerification { inner: Arc, state: Arc>, identities: IdentitiesBeingVerified, + we_started: bool, } impl std::fmt::Debug for QrVerification { @@ -115,6 +116,34 @@ impl QrVerification { self.identities.other_user_id() } + /// Get the device id of the other side. + pub fn other_device_id(&self) -> &DeviceId { + self.identities.other_device_id() + } + + /// Did we initiate the verification request + pub fn we_started(&self) -> bool { + self.we_started + } + + /// Get the `CancelCode` that cancelled this verification request. + pub fn cancel_code(&self) -> Option { + if let InnerState::Cancelled(c) = &*self.state.lock().unwrap() { + Some(c.state.cancel_code.to_owned()) + } else { + None + } + } + + /// Has the verification flow been cancelled by us. + pub fn cancelled_by_us(&self) -> Option { + if let InnerState::Cancelled(c) = &*self.state.lock().unwrap() { + Some(c.state.cancelled_by_us) + } else { + None + } + } + /// Has the verification flow completed. pub fn is_done(&self) -> bool { matches!(&*self.state.lock().unwrap(), InnerState::Done(_)) @@ -135,6 +164,14 @@ impl QrVerification { &self.flow_id } + /// Get the room id if the verification is happening inside a room. + pub fn room_id(&self) -> Option<&RoomId> { + match self.flow_id() { + FlowId::ToDevice(_) => None, + FlowId::InRoom(r, _) => Some(r), + } + } + /// Generate a QR code object that is representing this verification flow. /// /// The `QrCode` can then be rendered as an image or as an unicode string. @@ -159,6 +196,38 @@ impl QrVerification { self.cancel_with_code(CancelCode::User).map(|c| self.content_to_request(c)) } + /// Cancel the verification. + /// + /// This cancels the verification with given `CancelCode`. + /// + /// **Note**: This method should generally not be used, the [`cancel()`] + /// method should be preferred. The SDK will automatically cancel with the + /// approprate cancel code, user initiated cancellations should only cancel + /// with the `CancelCode::User` + /// + /// Returns None if the `Sas` object is already in a canceled state, + /// otherwise it returns a request that needs to be sent out. + /// + /// [`cancel()`]: #method.cancel + pub fn cancel_with_code(&self, code: CancelCode) -> Option { + let new_state = QrState::::new(true, code); + let content = new_state.as_content(self.flow_id()); + + let mut state = self.state.lock().unwrap(); + + match &*state { + InnerState::Confirmed(_) + | InnerState::Created(_) + | InnerState::Scanned(_) + | InnerState::Reciprocated(_) + | InnerState::Done(_) => { + *state = InnerState::Cancelled(new_state); + Some(content) + } + InnerState::Cancelled(_) => None, + } + } + /// Notify the other side that we have successfully scanned the QR code and /// that the QR verification flow can start. /// @@ -209,25 +278,6 @@ impl QrVerification { } } - fn cancel_with_code(&self, code: CancelCode) -> Option { - let new_state = QrState::::new(true, code); - let content = new_state.as_content(self.flow_id()); - - let mut state = self.state.lock().unwrap(); - - match &*state { - InnerState::Confirmed(_) - | InnerState::Created(_) - | InnerState::Scanned(_) - | InnerState::Reciprocated(_) - | InnerState::Done(_) => { - *state = InnerState::Cancelled(new_state); - Some(content) - } - InnerState::Cancelled(_) => None, - } - } - async fn mark_as_done( &self, new_state: QrState, @@ -351,6 +401,7 @@ impl QrVerification { own_master_key: String, other_device_key: String, identities: IdentitiesBeingVerified, + we_started: bool, ) -> Self { let secret = Self::generate_secret(); @@ -362,7 +413,7 @@ impl QrVerification { ) .into(); - Self::new_helper(store, flow_id, inner, identities) + Self::new_helper(store, flow_id, inner, identities, we_started) } pub(crate) fn new_self_no_master( @@ -371,6 +422,7 @@ impl QrVerification { flow_id: FlowId, own_master_key: String, identities: IdentitiesBeingVerified, + we_started: bool, ) -> QrVerification { let secret = Self::generate_secret(); @@ -382,7 +434,7 @@ impl QrVerification { ) .into(); - Self::new_helper(store, flow_id, inner, identities) + Self::new_helper(store, flow_id, inner, identities, we_started) } pub(crate) fn new_cross( @@ -391,6 +443,7 @@ impl QrVerification { own_master_key: String, other_master_key: String, identities: IdentitiesBeingVerified, + we_started: bool, ) -> Self { let secret = Self::generate_secret(); @@ -403,9 +456,10 @@ impl QrVerification { let inner: QrVerificationData = VerificationData::new(event_id, own_master_key, other_master_key, secret).into(); - Self::new_helper(store, flow_id, inner, identities) + Self::new_helper(store, flow_id, inner, identities, we_started) } + #[allow(clippy::too_many_arguments)] pub(crate) async fn from_scan( store: Arc, own_account: ReadOnlyAccount, @@ -414,6 +468,7 @@ impl QrVerification { other_device_id: DeviceIdBox, flow_id: FlowId, qr_code: QrVerificationData, + we_started: bool, ) -> Result { if flow_id.as_str() != qr_code.flow_id() { return Err(ScanError::FlowIdMismatch { @@ -510,6 +565,7 @@ impl QrVerification { })) .into(), identities, + we_started, }) } @@ -518,6 +574,7 @@ impl QrVerification { flow_id: FlowId, inner: QrVerificationData, identities: IdentitiesBeingVerified, + we_started: bool, ) -> Self { let secret = inner.secret().to_owned(); @@ -527,6 +584,7 @@ impl QrVerification { inner: inner.into(), state: Mutex::new(InnerState::Created(QrState { state: Created { secret } })).into(), identities, + we_started, } } } @@ -747,6 +805,7 @@ mod test { flow_id.clone(), master_key.clone(), identities.clone(), + false, ); assert_eq!(verification.inner.first_key(), &device_key); @@ -758,6 +817,7 @@ mod test { master_key.clone(), device_key.clone(), identities.clone(), + false, ); assert_eq!(verification.inner.first_key(), &master_key); @@ -775,6 +835,7 @@ mod test { master_key.clone(), bob_master_key.clone(), identities, + false, ); assert_eq!(verification.inner.first_key(), &master_key); @@ -818,6 +879,7 @@ mod test { flow_id.clone(), master_key.clone(), identities, + false, ); let bob_store = memory_store(); @@ -838,6 +900,7 @@ mod test { alice_account.device_id().to_owned(), flow_id, qr_code, + false, ) .await .unwrap(); diff --git a/matrix_sdk_crypto/src/verification/requests.rs b/matrix_sdk_crypto/src/verification/requests.rs index 14ed1f90..e858ceca 100644 --- a/matrix_sdk_crypto/src/verification/requests.rs +++ b/matrix_sdk_crypto/src/verification/requests.rs @@ -277,7 +277,7 @@ impl VerificationRequest { /// Generate a QR code that can be used by another client to start a QR code /// based verification. pub async fn generate_qr_code(&self) -> Result, CryptoStoreError> { - self.inner.lock().unwrap().generate_qr_code().await + self.inner.lock().unwrap().generate_qr_code(self.we_started).await } /// Start a QR code verification by providing a scanned QR code for this @@ -303,6 +303,7 @@ impl VerificationRequest { r.state.other_device_id.clone(), r.flow_id.as_ref().to_owned(), data, + self.we_started, ) .await?, )) @@ -550,11 +551,11 @@ impl InnerRequest { }) } - async fn generate_qr_code(&self) -> Result, CryptoStoreError> { + async fn generate_qr_code(&self, we_started: bool) -> Result, CryptoStoreError> { match self { InnerRequest::Created(_) => Ok(None), InnerRequest::Requested(_) => Ok(None), - InnerRequest::Ready(s) => s.generate_qr_code().await, + InnerRequest::Ready(s) => s.generate_qr_code(we_started).await, InnerRequest::Passive(_) => Ok(None), InnerRequest::Done(_) => Ok(None), InnerRequest::Cancelled(_) => Ok(None), @@ -783,7 +784,10 @@ impl RequestState { ) } - async fn generate_qr_code(&self) -> Result, CryptoStoreError> { + async fn generate_qr_code( + &self, + we_started: bool, + ) -> Result, CryptoStoreError> { // TODO return an error explaining why we can't generate a QR code? // If we didn't state that we support showing QR codes or if the other @@ -829,6 +833,7 @@ impl RequestState { .unwrap() .to_owned(), identites, + we_started, )) } else { Some(QrVerification::new_self_no_master( @@ -837,6 +842,7 @@ impl RequestState { self.flow_id.as_ref().to_owned(), i.master_key().get_first_key().unwrap().to_owned(), identites, + we_started, )) } } @@ -852,6 +858,7 @@ impl RequestState { .to_owned(), i.master_key().get_first_key().unwrap().to_owned(), identites, + we_started, )), } } else {