crypto: Add all the common accessors to the qr code verification

master
Damir Jelić 2021-06-25 17:55:39 +02:00
parent 728d298810
commit 80a30bcdd6
2 changed files with 97 additions and 27 deletions

View File

@ -33,7 +33,7 @@ use ruma::{
}, },
AnyMessageEventContent, AnyToDeviceEventContent, AnyMessageEventContent, AnyToDeviceEventContent,
}, },
DeviceIdBox, DeviceKeyAlgorithm, UserId, DeviceId, DeviceIdBox, DeviceKeyAlgorithm, RoomId, UserId,
}; };
use thiserror::Error; use thiserror::Error;
@ -83,6 +83,7 @@ pub struct QrVerification {
inner: Arc<QrVerificationData>, inner: Arc<QrVerificationData>,
state: Arc<Mutex<InnerState>>, state: Arc<Mutex<InnerState>>,
identities: IdentitiesBeingVerified, identities: IdentitiesBeingVerified,
we_started: bool,
} }
impl std::fmt::Debug for QrVerification { impl std::fmt::Debug for QrVerification {
@ -115,6 +116,34 @@ impl QrVerification {
self.identities.other_user_id() 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<CancelCode> {
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<bool> {
if let InnerState::Cancelled(c) = &*self.state.lock().unwrap() {
Some(c.state.cancelled_by_us)
} else {
None
}
}
/// Has the verification flow completed. /// Has the verification flow completed.
pub fn is_done(&self) -> bool { pub fn is_done(&self) -> bool {
matches!(&*self.state.lock().unwrap(), InnerState::Done(_)) matches!(&*self.state.lock().unwrap(), InnerState::Done(_))
@ -135,6 +164,14 @@ impl QrVerification {
&self.flow_id &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. /// 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. /// 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)) 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<OutgoingContent> {
let new_state = QrState::<Cancelled>::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 /// Notify the other side that we have successfully scanned the QR code and
/// that the QR verification flow can start. /// that the QR verification flow can start.
/// ///
@ -209,25 +278,6 @@ impl QrVerification {
} }
} }
fn cancel_with_code(&self, code: CancelCode) -> Option<OutgoingContent> {
let new_state = QrState::<Cancelled>::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( async fn mark_as_done(
&self, &self,
new_state: QrState<Done>, new_state: QrState<Done>,
@ -351,6 +401,7 @@ impl QrVerification {
own_master_key: String, own_master_key: String,
other_device_key: String, other_device_key: String,
identities: IdentitiesBeingVerified, identities: IdentitiesBeingVerified,
we_started: bool,
) -> Self { ) -> Self {
let secret = Self::generate_secret(); let secret = Self::generate_secret();
@ -362,7 +413,7 @@ impl QrVerification {
) )
.into(); .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( pub(crate) fn new_self_no_master(
@ -371,6 +422,7 @@ impl QrVerification {
flow_id: FlowId, flow_id: FlowId,
own_master_key: String, own_master_key: String,
identities: IdentitiesBeingVerified, identities: IdentitiesBeingVerified,
we_started: bool,
) -> QrVerification { ) -> QrVerification {
let secret = Self::generate_secret(); let secret = Self::generate_secret();
@ -382,7 +434,7 @@ impl QrVerification {
) )
.into(); .into();
Self::new_helper(store, flow_id, inner, identities) Self::new_helper(store, flow_id, inner, identities, we_started)
} }
pub(crate) fn new_cross( pub(crate) fn new_cross(
@ -391,6 +443,7 @@ impl QrVerification {
own_master_key: String, own_master_key: String,
other_master_key: String, other_master_key: String,
identities: IdentitiesBeingVerified, identities: IdentitiesBeingVerified,
we_started: bool,
) -> Self { ) -> Self {
let secret = Self::generate_secret(); let secret = Self::generate_secret();
@ -403,9 +456,10 @@ impl QrVerification {
let inner: QrVerificationData = let inner: QrVerificationData =
VerificationData::new(event_id, own_master_key, other_master_key, secret).into(); 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( pub(crate) async fn from_scan(
store: Arc<dyn CryptoStore>, store: Arc<dyn CryptoStore>,
own_account: ReadOnlyAccount, own_account: ReadOnlyAccount,
@ -414,6 +468,7 @@ impl QrVerification {
other_device_id: DeviceIdBox, other_device_id: DeviceIdBox,
flow_id: FlowId, flow_id: FlowId,
qr_code: QrVerificationData, qr_code: QrVerificationData,
we_started: bool,
) -> Result<Self, ScanError> { ) -> Result<Self, ScanError> {
if flow_id.as_str() != qr_code.flow_id() { if flow_id.as_str() != qr_code.flow_id() {
return Err(ScanError::FlowIdMismatch { return Err(ScanError::FlowIdMismatch {
@ -510,6 +565,7 @@ impl QrVerification {
})) }))
.into(), .into(),
identities, identities,
we_started,
}) })
} }
@ -518,6 +574,7 @@ impl QrVerification {
flow_id: FlowId, flow_id: FlowId,
inner: QrVerificationData, inner: QrVerificationData,
identities: IdentitiesBeingVerified, identities: IdentitiesBeingVerified,
we_started: bool,
) -> Self { ) -> Self {
let secret = inner.secret().to_owned(); let secret = inner.secret().to_owned();
@ -527,6 +584,7 @@ impl QrVerification {
inner: inner.into(), inner: inner.into(),
state: Mutex::new(InnerState::Created(QrState { state: Created { secret } })).into(), state: Mutex::new(InnerState::Created(QrState { state: Created { secret } })).into(),
identities, identities,
we_started,
} }
} }
} }
@ -747,6 +805,7 @@ mod test {
flow_id.clone(), flow_id.clone(),
master_key.clone(), master_key.clone(),
identities.clone(), identities.clone(),
false,
); );
assert_eq!(verification.inner.first_key(), &device_key); assert_eq!(verification.inner.first_key(), &device_key);
@ -758,6 +817,7 @@ mod test {
master_key.clone(), master_key.clone(),
device_key.clone(), device_key.clone(),
identities.clone(), identities.clone(),
false,
); );
assert_eq!(verification.inner.first_key(), &master_key); assert_eq!(verification.inner.first_key(), &master_key);
@ -775,6 +835,7 @@ mod test {
master_key.clone(), master_key.clone(),
bob_master_key.clone(), bob_master_key.clone(),
identities, identities,
false,
); );
assert_eq!(verification.inner.first_key(), &master_key); assert_eq!(verification.inner.first_key(), &master_key);
@ -818,6 +879,7 @@ mod test {
flow_id.clone(), flow_id.clone(),
master_key.clone(), master_key.clone(),
identities, identities,
false,
); );
let bob_store = memory_store(); let bob_store = memory_store();
@ -838,6 +900,7 @@ mod test {
alice_account.device_id().to_owned(), alice_account.device_id().to_owned(),
flow_id, flow_id,
qr_code, qr_code,
false,
) )
.await .await
.unwrap(); .unwrap();

View File

@ -277,7 +277,7 @@ impl VerificationRequest {
/// Generate a QR code that can be used by another client to start a QR code /// Generate a QR code that can be used by another client to start a QR code
/// based verification. /// based verification.
pub async fn generate_qr_code(&self) -> Result<Option<QrVerification>, CryptoStoreError> { pub async fn generate_qr_code(&self) -> Result<Option<QrVerification>, 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 /// 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.state.other_device_id.clone(),
r.flow_id.as_ref().to_owned(), r.flow_id.as_ref().to_owned(),
data, data,
self.we_started,
) )
.await?, .await?,
)) ))
@ -550,11 +551,11 @@ impl InnerRequest {
}) })
} }
async fn generate_qr_code(&self) -> Result<Option<QrVerification>, CryptoStoreError> { async fn generate_qr_code(&self, we_started: bool) -> Result<Option<QrVerification>, CryptoStoreError> {
match self { match self {
InnerRequest::Created(_) => Ok(None), InnerRequest::Created(_) => Ok(None),
InnerRequest::Requested(_) => 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::Passive(_) => Ok(None),
InnerRequest::Done(_) => Ok(None), InnerRequest::Done(_) => Ok(None),
InnerRequest::Cancelled(_) => Ok(None), InnerRequest::Cancelled(_) => Ok(None),
@ -783,7 +784,10 @@ impl RequestState<Ready> {
) )
} }
async fn generate_qr_code(&self) -> Result<Option<QrVerification>, CryptoStoreError> { async fn generate_qr_code(
&self,
we_started: bool,
) -> Result<Option<QrVerification>, CryptoStoreError> {
// TODO return an error explaining why we can't generate a QR code? // 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 // If we didn't state that we support showing QR codes or if the other
@ -829,6 +833,7 @@ impl RequestState<Ready> {
.unwrap() .unwrap()
.to_owned(), .to_owned(),
identites, identites,
we_started,
)) ))
} else { } else {
Some(QrVerification::new_self_no_master( Some(QrVerification::new_self_no_master(
@ -837,6 +842,7 @@ impl RequestState<Ready> {
self.flow_id.as_ref().to_owned(), self.flow_id.as_ref().to_owned(),
i.master_key().get_first_key().unwrap().to_owned(), i.master_key().get_first_key().unwrap().to_owned(),
identites, identites,
we_started,
)) ))
} }
} }
@ -852,6 +858,7 @@ impl RequestState<Ready> {
.to_owned(), .to_owned(),
i.master_key().get_first_key().unwrap().to_owned(), i.master_key().get_first_key().unwrap().to_owned(),
identites, identites,
we_started,
)), )),
} }
} else { } else {