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

This commit is contained in:
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,
},
DeviceIdBox, DeviceKeyAlgorithm, UserId,
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, RoomId, UserId,
};
use thiserror::Error;
@ -83,6 +83,7 @@ pub struct QrVerification {
inner: Arc<QrVerificationData>,
state: Arc<Mutex<InnerState>>,
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<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.
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<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
/// 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(
&self,
new_state: QrState<Done>,
@ -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<dyn CryptoStore>,
own_account: ReadOnlyAccount,
@ -414,6 +468,7 @@ impl QrVerification {
other_device_id: DeviceIdBox,
flow_id: FlowId,
qr_code: QrVerificationData,
we_started: bool,
) -> Result<Self, ScanError> {
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();

View file

@ -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<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
@ -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<Option<QrVerification>, CryptoStoreError> {
async fn generate_qr_code(&self, we_started: bool) -> Result<Option<QrVerification>, 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<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?
// If we didn't state that we support showing QR codes or if the other
@ -829,6 +833,7 @@ impl RequestState<Ready> {
.unwrap()
.to_owned(),
identites,
we_started,
))
} else {
Some(QrVerification::new_self_no_master(
@ -837,6 +842,7 @@ impl RequestState<Ready> {
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<Ready> {
.to_owned(),
i.master_key().get_first_key().unwrap().to_owned(),
identites,
we_started,
)),
}
} else {