matrix-sdk: Rework the public API for answering verifications
parent
baee5b2d11
commit
3cf843d24f
|
@ -11,11 +11,12 @@ use matrix_sdk::{
|
||||||
self,
|
self,
|
||||||
events::{room::message::MessageType, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent},
|
events::{room::message::MessageType, AnySyncMessageEvent, AnySyncRoomEvent, AnyToDeviceEvent},
|
||||||
identifiers::UserId,
|
identifiers::UserId,
|
||||||
Client, LoopCtrl, Sas, SyncSettings,
|
verification::{SasVerification, Verification},
|
||||||
|
Client, LoopCtrl, SyncSettings,
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
async fn wait_for_confirmation(client: Client, sas: Sas) {
|
async fn wait_for_confirmation(client: Client, sas: SasVerification) {
|
||||||
println!("Does the emoji match: {:?}", sas.emoji());
|
println!("Does the emoji match: {:?}", sas.emoji());
|
||||||
|
|
||||||
let mut input = String::new();
|
let mut input = String::new();
|
||||||
|
@ -34,7 +35,7 @@ async fn wait_for_confirmation(client: Client, sas: Sas) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_result(sas: &Sas) {
|
fn print_result(sas: &SasVerification) {
|
||||||
let device = sas.other_device();
|
let device = sas.other_device();
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
|
@ -80,37 +81,35 @@ async fn login(
|
||||||
for event in response.to_device.events.iter().filter_map(|e| e.deserialize().ok()) {
|
for event in response.to_device.events.iter().filter_map(|e| e.deserialize().ok()) {
|
||||||
match event {
|
match event {
|
||||||
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
||||||
let sas = client
|
if let Some(Verification::SasV1(sas)) =
|
||||||
.get_verification(&e.sender, &e.content.transaction_id)
|
client.get_verification(&e.sender, &e.content.transaction_id).await
|
||||||
.await
|
{
|
||||||
.expect("Sas object wasn't created");
|
println!(
|
||||||
println!(
|
"Starting verification with {} {}",
|
||||||
"Starting verification with {} {}",
|
&sas.other_device().user_id(),
|
||||||
&sas.other_device().user_id(),
|
&sas.other_device().device_id()
|
||||||
&sas.other_device().device_id()
|
);
|
||||||
);
|
print_devices(&e.sender, client).await;
|
||||||
print_devices(&e.sender, client).await;
|
sas.accept().await.unwrap();
|
||||||
sas.accept().await.unwrap();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyToDeviceEvent::KeyVerificationKey(e) => {
|
AnyToDeviceEvent::KeyVerificationKey(e) => {
|
||||||
let sas = client
|
if let Some(Verification::SasV1(sas)) =
|
||||||
.get_verification(&e.sender, &e.content.transaction_id)
|
client.get_verification(&e.sender, &e.content.transaction_id).await
|
||||||
.await
|
{
|
||||||
.expect("Sas object wasn't created");
|
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
||||||
|
}
|
||||||
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnyToDeviceEvent::KeyVerificationMac(e) => {
|
AnyToDeviceEvent::KeyVerificationMac(e) => {
|
||||||
let sas = client
|
if let Some(Verification::SasV1(sas)) =
|
||||||
.get_verification(&e.sender, &e.content.transaction_id)
|
client.get_verification(&e.sender, &e.content.transaction_id).await
|
||||||
.await
|
{
|
||||||
.expect("Sas object wasn't created");
|
if sas.is_done() {
|
||||||
|
print_result(&sas);
|
||||||
if sas.is_done() {
|
print_devices(&e.sender, client).await;
|
||||||
print_result(&sas);
|
}
|
||||||
print_devices(&e.sender, client).await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,28 +139,28 @@ async fn login(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnySyncMessageEvent::KeyVerificationKey(e) => {
|
AnySyncMessageEvent::KeyVerificationKey(e) => {
|
||||||
let sas = client
|
if let Some(Verification::SasV1(sas)) = client
|
||||||
.get_verification(
|
.get_verification(
|
||||||
&e.sender,
|
&e.sender,
|
||||||
e.content.relation.event_id.as_str(),
|
e.content.relation.event_id.as_str(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Sas object wasn't created");
|
{
|
||||||
|
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
||||||
tokio::spawn(wait_for_confirmation((*client).clone(), sas));
|
}
|
||||||
}
|
}
|
||||||
AnySyncMessageEvent::KeyVerificationMac(e) => {
|
AnySyncMessageEvent::KeyVerificationMac(e) => {
|
||||||
let sas = client
|
if let Some(Verification::SasV1(sas)) = client
|
||||||
.get_verification(
|
.get_verification(
|
||||||
&e.sender,
|
&e.sender,
|
||||||
e.content.relation.event_id.as_str(),
|
e.content.relation.event_id.as_str(),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.expect("Sas object wasn't created");
|
{
|
||||||
|
if sas.is_done() {
|
||||||
if sas.is_done() {
|
print_result(&sas);
|
||||||
print_result(&sas);
|
print_devices(&e.sender, client).await;
|
||||||
print_devices(&e.sender, client).await;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
|
|
@ -126,8 +126,7 @@ use ruma::{
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
use crate::{
|
use crate::{
|
||||||
device::{Device, UserDevices},
|
device::{Device, UserDevices},
|
||||||
sas::Sas,
|
verification::{QrVerification, SasVerification, Verification, VerificationRequest},
|
||||||
verification_request::VerificationRequest,
|
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
error::HttpError,
|
error::HttpError,
|
||||||
|
@ -2182,14 +2181,19 @@ impl Client {
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `Sas` verification object with the given flow id.
|
/// Get a verification object with the given flow id.
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
pub async fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Sas> {
|
pub async fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Verification> {
|
||||||
self.base_client
|
let olm = self.base_client.olm_machine().await?;
|
||||||
.get_verification(user_id, flow_id)
|
olm.get_verification(user_id, flow_id).map(|v| match v {
|
||||||
.await
|
matrix_sdk_base::crypto::Verification::SasV1(s) => {
|
||||||
.map(|sas| Sas { inner: sas, client: self.clone() })
|
SasVerification { inner: s, client: self.clone() }.into()
|
||||||
|
}
|
||||||
|
matrix_sdk_base::crypto::Verification::QrV1(qr) => {
|
||||||
|
QrVerification { inner: qr, client: self.clone() }.into()
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `VerificationRequest` object for the given user with the given
|
/// Get a `VerificationRequest` object for the given user with the given
|
||||||
|
@ -2697,6 +2701,22 @@ impl Client {
|
||||||
let request = whoami::Request::new();
|
let request = whoami::Request::new();
|
||||||
self.send(request, None).await
|
self.send(request, None).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn send_verification_request(
|
||||||
|
&self,
|
||||||
|
request: matrix_sdk_base::crypto::OutgoingVerificationRequest,
|
||||||
|
) -> Result<()> {
|
||||||
|
match request {
|
||||||
|
matrix_sdk_base::crypto::OutgoingVerificationRequest::ToDevice(t) => {
|
||||||
|
self.send_to_device(&t).await?;
|
||||||
|
}
|
||||||
|
matrix_sdk_base::crypto::OutgoingVerificationRequest::InRoom(r) => {
|
||||||
|
self.room_send_helper(&r).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -20,7 +20,7 @@ use matrix_sdk_base::crypto::{
|
||||||
};
|
};
|
||||||
use ruma::{DeviceId, DeviceIdBox};
|
use ruma::{DeviceId, DeviceIdBox};
|
||||||
|
|
||||||
use crate::{error::Result, Client, Sas};
|
use crate::{error::Result, verification::SasVerification, Client};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// A device represents a E2EE capable client of an user.
|
/// A device represents a E2EE capable client of an user.
|
||||||
|
@ -62,11 +62,11 @@ impl Device {
|
||||||
/// let verification = device.start_verification().await.unwrap();
|
/// let verification = device.start_verification().await.unwrap();
|
||||||
/// # });
|
/// # });
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn start_verification(&self) -> Result<Sas> {
|
pub async fn start_verification(&self) -> Result<SasVerification> {
|
||||||
let (sas, request) = self.inner.start_verification().await?;
|
let (sas, request) = self.inner.start_verification().await?;
|
||||||
self.client.send_to_device(&request).await?;
|
self.client.send_to_device(&request).await?;
|
||||||
|
|
||||||
Ok(Sas { inner: sas, client: self.client.clone() })
|
Ok(SasVerification { inner: sas, client: self.client.clone() })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is the device trusted.
|
/// Is the device trusted.
|
||||||
|
|
|
@ -115,9 +115,7 @@ mod room_member;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
mod device;
|
mod device;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
mod sas;
|
pub mod verification;
|
||||||
#[cfg(feature = "encryption")]
|
|
||||||
mod verification_request;
|
|
||||||
|
|
||||||
pub use client::{Client, ClientConfig, LoopCtrl, RequestConfig, SyncSettings};
|
pub use client::{Client, ClientConfig, LoopCtrl, RequestConfig, SyncSettings};
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
|
@ -127,12 +125,5 @@ pub use error::{Error, HttpError, Result};
|
||||||
pub use event_handler::{CustomEvent, EventHandler};
|
pub use event_handler::{CustomEvent, EventHandler};
|
||||||
pub use http_client::HttpSend;
|
pub use http_client::HttpSend;
|
||||||
pub use room_member::RoomMember;
|
pub use room_member::RoomMember;
|
||||||
#[cfg(feature = "encryption")]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
||||||
pub use sas::Sas;
|
|
||||||
#[cfg(feature = "encryption")]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
||||||
pub use verification_request::VerificationRequest;
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! Interactive verification for E2EE capable users and devices in Matrix.
|
||||||
|
//!
|
||||||
|
//! The SDK supports interactive verification of devices and users, this module
|
||||||
|
//! contains types that model and support different verification flows.
|
||||||
|
//!
|
||||||
|
//! A verification flow usually starts its life as a [VerificationRequest], the
|
||||||
|
//! request can then be accepted, or it needs to be accepted by the other side
|
||||||
|
//! of the verification flow.
|
||||||
|
//!
|
||||||
|
//! Once both sides have agreed to pereform the verification, and the
|
||||||
|
//! [VerificationRequest::is_ready()] method returns true, the verification can
|
||||||
|
//! transition into one of the supported verification flows:
|
||||||
|
//!
|
||||||
|
//! * [SasVerification] - Interactive verification using a short authentication
|
||||||
|
//! string.
|
||||||
|
//! * [QrVerification] - Interactive verification using QR codes.
|
||||||
|
|
||||||
|
mod qrcode;
|
||||||
|
mod requests;
|
||||||
|
mod sas;
|
||||||
|
|
||||||
|
pub use qrcode::QrVerification;
|
||||||
|
pub use requests::VerificationRequest;
|
||||||
|
pub use sas::SasVerification;
|
||||||
|
|
||||||
|
/// An enum over the different verification types the SDK supports.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum Verification {
|
||||||
|
/// The `m.sas.v1` verification variant.
|
||||||
|
SasV1(SasVerification),
|
||||||
|
/// The `m.qr_code.*.v1` verification variant.
|
||||||
|
QrV1(QrVerification),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Verification {
|
||||||
|
/// Try to deconstruct this verification enum into a SAS verification.
|
||||||
|
pub fn sas(self) -> Option<SasVerification> {
|
||||||
|
if let Verification::SasV1(sas) = self {
|
||||||
|
Some(sas)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to deconstruct this verification enum into a QR code verification.
|
||||||
|
pub fn qr(self) -> Option<QrVerification> {
|
||||||
|
if let Verification::QrV1(qr) = self {
|
||||||
|
Some(qr)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has this verification finished.
|
||||||
|
pub fn is_done(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Verification::SasV1(s) => s.is_done(),
|
||||||
|
Verification::QrV1(qr) => qr.is_done(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has the verification been cancelled.
|
||||||
|
pub fn is_cancelled(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Verification::SasV1(s) => s.is_cancelled(),
|
||||||
|
Verification::QrV1(qr) => qr.is_cancelled(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get our own user id.
|
||||||
|
pub fn own_user_id(&self) -> &ruma::UserId {
|
||||||
|
match self {
|
||||||
|
Verification::SasV1(v) => v.own_user_id(),
|
||||||
|
Verification::QrV1(v) => v.own_user_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the user id of the other user participating in this verification
|
||||||
|
/// flow.
|
||||||
|
pub fn other_user_id(&self) -> &ruma::UserId {
|
||||||
|
match self {
|
||||||
|
Verification::SasV1(v) => v.inner.other_user_id(),
|
||||||
|
Verification::QrV1(v) => v.inner.other_user_id(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this a verification that is veryfying one of our own devices.
|
||||||
|
pub fn is_self_verification(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
Verification::SasV1(v) => v.is_self_verification(),
|
||||||
|
Verification::QrV1(v) => v.is_self_verification(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SasVerification> for Verification {
|
||||||
|
fn from(sas: SasVerification) -> Self {
|
||||||
|
Self::SasV1(sas)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<QrVerification> for Verification {
|
||||||
|
fn from(qr: QrVerification) -> Self {
|
||||||
|
Self::QrV1(qr)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use matrix_sdk_base::crypto::{
|
||||||
|
matrix_qrcode::{qrcode::QrCode, EncodingError},
|
||||||
|
QrVerification as BaseQrVerification,
|
||||||
|
};
|
||||||
|
use ruma::UserId;
|
||||||
|
|
||||||
|
use crate::{Client, Result};
|
||||||
|
|
||||||
|
/// An object controlling QR code style key verification flows.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct QrVerification {
|
||||||
|
pub(crate) inner: BaseQrVerification,
|
||||||
|
pub(crate) client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QrVerification {
|
||||||
|
/// Get our own user id.
|
||||||
|
pub fn own_user_id(&self) -> &UserId {
|
||||||
|
self.inner.user_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this a verification that is veryfying one of our own devices.
|
||||||
|
pub fn is_self_verification(&self) -> bool {
|
||||||
|
self.inner.is_self_verification()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has this verification finished.
|
||||||
|
pub fn is_done(&self) -> bool {
|
||||||
|
self.inner.is_done()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has the verification been cancelled.
|
||||||
|
pub fn is_cancelled(&self) -> bool {
|
||||||
|
self.inner.is_cancelled()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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 [`to_bytes()`](#method.to_bytes) method can be used to instead
|
||||||
|
/// output the raw bytes that should be encoded as a QR code.
|
||||||
|
pub fn to_qr_code(&self) -> std::result::Result<QrCode, EncodingError> {
|
||||||
|
self.inner.to_qr_code()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a the raw bytes that should be encoded as a QR code is
|
||||||
|
/// representing this verification flow.
|
||||||
|
///
|
||||||
|
/// The [`to_qr_code()`](#method.to_qr_code) method can be used to instead
|
||||||
|
/// output a `QrCode` object that can be rendered.
|
||||||
|
pub fn to_bytes(&self) -> std::result::Result<Vec<u8>, EncodingError> {
|
||||||
|
self.inner.to_bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Confirm that the other side has scanned our QR code.
|
||||||
|
pub async fn confirm(&self) -> Result<()> {
|
||||||
|
if let Some(request) = self.inner.confirm_scanning() {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Abort the verification flow and notify the other side that we did so.
|
||||||
|
pub async fn cancel(&self) -> Result<()> {
|
||||||
|
if let Some(request) = self.inner.cancel() {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use matrix_sdk_base::crypto::VerificationRequest as BaseVerificationRequest;
|
||||||
|
use ruma::events::key::verification::VerificationMethod;
|
||||||
|
|
||||||
|
use super::{QrVerification, SasVerification};
|
||||||
|
use crate::{Client, Result};
|
||||||
|
|
||||||
|
/// An object controlling the interactive verification flow.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct VerificationRequest {
|
||||||
|
pub(crate) inner: BaseVerificationRequest,
|
||||||
|
pub(crate) client: Client,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VerificationRequest {
|
||||||
|
/// Has this verification finished.
|
||||||
|
pub fn is_done(&self) -> bool {
|
||||||
|
self.inner.is_done()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has the verification been cancelled.
|
||||||
|
pub fn is_cancelled(&self) -> bool {
|
||||||
|
self.inner.is_cancelled()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get our own user id.
|
||||||
|
pub fn own_user_id(&self) -> &ruma::UserId {
|
||||||
|
self.inner.own_user_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Has the verification request been answered by another device.
|
||||||
|
pub fn is_passive(&self) -> bool {
|
||||||
|
self.inner.is_passive()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the verification request ready to start a verification flow.
|
||||||
|
pub fn is_ready(&self) -> bool {
|
||||||
|
self.inner.is_ready()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the user id of the other user participating in this verification
|
||||||
|
/// flow.
|
||||||
|
pub fn other_user_id(&self) -> &ruma::UserId {
|
||||||
|
self.inner.other_user()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is this a verification that is veryfying one of our own devices.
|
||||||
|
pub fn is_self_verification(&self) -> bool {
|
||||||
|
self.inner.is_self_verification()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the supported verification methods of the other side.
|
||||||
|
///
|
||||||
|
/// Will be present only if the other side requested the verification or if
|
||||||
|
/// we're in the ready state.
|
||||||
|
pub fn their_supported_methods(&self) -> Option<Vec<VerificationMethod>> {
|
||||||
|
self.inner.their_supported_methods()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accept the verification request.
|
||||||
|
///
|
||||||
|
/// This method will accept the request and signal that it supports the
|
||||||
|
/// `m.sas.v1`, the `m.qr_code.show.v1`, and `m.reciprocate.v1` method.
|
||||||
|
///
|
||||||
|
/// If QR code scanning should be supported or QR code showing shouldn't be
|
||||||
|
/// supported the [`accept_with_methods()`] method should be used instead.
|
||||||
|
///
|
||||||
|
/// [`accept_with_methods()`]: #method.accept_with_methods
|
||||||
|
pub async fn accept(&self) -> Result<()> {
|
||||||
|
if let Some(request) = self.inner.accept() {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Accept the verification request signaling that our client supports the
|
||||||
|
/// given verification methods.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `methods` - The methods that we should advertise as supported by us.
|
||||||
|
pub async fn accept_with_methods(&self, methods: Vec<VerificationMethod>) -> Result<()> {
|
||||||
|
if let Some(request) = self.inner.accept_with_methods(methods) {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a QR code
|
||||||
|
pub async fn generate_qr_code(&self) -> Result<Option<QrVerification>> {
|
||||||
|
Ok(self
|
||||||
|
.inner
|
||||||
|
.generate_qr_code()
|
||||||
|
.await?
|
||||||
|
.map(|qr| QrVerification { inner: qr, client: self.client.clone() }))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transition from this verification request into a SAS verification flow.
|
||||||
|
pub async fn start_sas(&self) -> Result<Option<SasVerification>> {
|
||||||
|
if let Some((sas, request)) = self.inner.start_sas().await? {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
|
||||||
|
Ok(Some(SasVerification { inner: sas, client: self.client.clone() }))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cancel the verification request
|
||||||
|
pub async fn cancel(&self) -> Result<()> {
|
||||||
|
if let Some(request) = self.inner.cancel() {
|
||||||
|
self.client.send_verification_request(request).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,21 +12,19 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use matrix_sdk_base::crypto::{
|
use matrix_sdk_base::crypto::{AcceptSettings, ReadOnlyDevice, Sas as BaseSas};
|
||||||
AcceptSettings, OutgoingVerificationRequest, ReadOnlyDevice, Sas as BaseSas,
|
|
||||||
};
|
|
||||||
use ruma::UserId;
|
use ruma::UserId;
|
||||||
|
|
||||||
use crate::{error::Result, Client};
|
use crate::{error::Result, Client};
|
||||||
|
|
||||||
/// An object controlling the interactive verification flow.
|
/// An object controlling the interactive verification flow.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Sas {
|
pub struct SasVerification {
|
||||||
pub(crate) inner: BaseSas,
|
pub(crate) inner: BaseSas,
|
||||||
pub(crate) client: Client,
|
pub(crate) client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sas {
|
impl SasVerification {
|
||||||
/// Accept the interactive verification flow.
|
/// Accept the interactive verification flow.
|
||||||
pub async fn accept(&self) -> Result<()> {
|
pub async fn accept(&self) -> Result<()> {
|
||||||
self.accept_with_settings(Default::default()).await
|
self.accept_with_settings(Default::default()).await
|
||||||
|
@ -45,7 +43,7 @@ impl Sas {
|
||||||
/// # use futures::executor::block_on;
|
/// # use futures::executor::block_on;
|
||||||
/// # use url::Url;
|
/// # use url::Url;
|
||||||
/// # use ruma::identifiers::user_id;
|
/// # use ruma::identifiers::user_id;
|
||||||
/// use matrix_sdk::Sas;
|
/// use matrix_sdk::verification::SasVerification;
|
||||||
/// use matrix_sdk_base::crypto::AcceptSettings;
|
/// use matrix_sdk_base::crypto::AcceptSettings;
|
||||||
/// use matrix_sdk::events::key::verification::ShortAuthenticationString;
|
/// use matrix_sdk::events::key::verification::ShortAuthenticationString;
|
||||||
/// # let homeserver = Url::parse("http://example.com").unwrap();
|
/// # let homeserver = Url::parse("http://example.com").unwrap();
|
||||||
|
@ -56,6 +54,8 @@ impl Sas {
|
||||||
/// let sas = client
|
/// let sas = client
|
||||||
/// .get_verification(&user_id, flow_id)
|
/// .get_verification(&user_id, flow_id)
|
||||||
/// .await
|
/// .await
|
||||||
|
/// .unwrap()
|
||||||
|
/// .sas()
|
||||||
/// .unwrap();
|
/// .unwrap();
|
||||||
///
|
///
|
||||||
/// let only_decimal = AcceptSettings::with_allowed_methods(
|
/// let only_decimal = AcceptSettings::with_allowed_methods(
|
||||||
|
@ -65,15 +65,8 @@ impl Sas {
|
||||||
/// # });
|
/// # });
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn accept_with_settings(&self, settings: AcceptSettings) -> Result<()> {
|
pub async fn accept_with_settings(&self, settings: AcceptSettings) -> Result<()> {
|
||||||
if let Some(req) = self.inner.accept_with_settings(settings) {
|
if let Some(request) = self.inner.accept_with_settings(settings) {
|
||||||
match req {
|
self.client.send_verification_request(request).await?;
|
||||||
OutgoingVerificationRequest::ToDevice(r) => {
|
|
||||||
self.client.send_to_device(&r).await?;
|
|
||||||
}
|
|
||||||
OutgoingVerificationRequest::InRoom(r) => {
|
|
||||||
self.client.room_send_helper(&r).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -82,16 +75,8 @@ impl Sas {
|
||||||
pub async fn confirm(&self) -> Result<()> {
|
pub async fn confirm(&self) -> Result<()> {
|
||||||
let (request, signature) = self.inner.confirm().await?;
|
let (request, signature) = self.inner.confirm().await?;
|
||||||
|
|
||||||
match request {
|
if let Some(request) = request {
|
||||||
Some(OutgoingVerificationRequest::InRoom(r)) => {
|
self.client.send_verification_request(request).await?;
|
||||||
self.client.room_send_helper(&r).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(OutgoingVerificationRequest::ToDevice(r)) => {
|
|
||||||
self.client.send_to_device(&r).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
None => (),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(s) = signature {
|
if let Some(s) = signature {
|
||||||
|
@ -104,14 +89,7 @@ impl Sas {
|
||||||
/// Cancel the interactive verification flow.
|
/// Cancel the interactive verification flow.
|
||||||
pub async fn cancel(&self) -> Result<()> {
|
pub async fn cancel(&self) -> Result<()> {
|
||||||
if let Some(request) = self.inner.cancel() {
|
if let Some(request) = self.inner.cancel() {
|
||||||
match request {
|
self.client.send_verification_request(request).await?;
|
||||||
OutgoingVerificationRequest::ToDevice(r) => {
|
|
||||||
self.client.send_to_device(&r).await?;
|
|
||||||
}
|
|
||||||
OutgoingVerificationRequest::InRoom(r) => {
|
|
||||||
self.client.room_send_helper(&r).await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -138,6 +116,11 @@ impl Sas {
|
||||||
self.inner.is_done()
|
self.inner.is_done()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Are we in a state where we can show the short auth string.
|
||||||
|
pub fn can_be_presented(&self) -> bool {
|
||||||
|
self.inner.can_be_presented()
|
||||||
|
}
|
||||||
|
|
||||||
/// Is the verification process canceled.
|
/// Is the verification process canceled.
|
||||||
pub fn is_cancelled(&self) -> bool {
|
pub fn is_cancelled(&self) -> bool {
|
||||||
self.inner.is_cancelled()
|
self.inner.is_cancelled()
|
|
@ -1,49 +0,0 @@
|
||||||
// Copyright 2020 The Matrix.org Foundation C.I.C.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
use matrix_sdk_base::crypto::{
|
|
||||||
OutgoingVerificationRequest, VerificationRequest as BaseVerificationRequest,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::{Client, Result};
|
|
||||||
|
|
||||||
/// An object controlling the interactive verification flow.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct VerificationRequest {
|
|
||||||
pub(crate) inner: BaseVerificationRequest,
|
|
||||||
pub(crate) client: Client,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VerificationRequest {
|
|
||||||
/// Accept the verification request
|
|
||||||
pub async fn accept(&self) -> Result<()> {
|
|
||||||
if let Some(request) = self.inner.accept() {
|
|
||||||
match request {
|
|
||||||
OutgoingVerificationRequest::ToDevice(r) => {
|
|
||||||
self.client.send_to_device(&r).await?;
|
|
||||||
}
|
|
||||||
OutgoingVerificationRequest::InRoom(r) => {
|
|
||||||
self.client.room_send_helper(&r).await?;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Cancel the verification request
|
|
||||||
pub async fn cancel(&self) -> Result<()> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,7 +36,7 @@ use matrix_sdk_common::{locks::Mutex, uuid::Uuid};
|
||||||
use matrix_sdk_crypto::{
|
use matrix_sdk_crypto::{
|
||||||
store::{CryptoStore, CryptoStoreError},
|
store::{CryptoStore, CryptoStoreError},
|
||||||
Device, EncryptionSettings, IncomingResponse, MegolmError, OlmError, OlmMachine,
|
Device, EncryptionSettings, IncomingResponse, MegolmError, OlmError, OlmMachine,
|
||||||
OutgoingRequest, Sas, ToDeviceRequest, UserDevices,
|
OutgoingRequest, ToDeviceRequest, UserDevices,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
use ruma::{
|
use ruma::{
|
||||||
|
@ -1202,26 +1202,6 @@ impl BaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a `Sas` verification object with the given flow id.
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `flow_id` - The unique id that identifies a interactive verification
|
|
||||||
/// flow. For in-room verifications this will be the event id of the
|
|
||||||
/// *m.key.verification.request* event that started the flow, for the
|
|
||||||
/// to-device verification flows this will be the transaction id of the
|
|
||||||
/// *m.key.verification.start* event.
|
|
||||||
#[cfg(feature = "encryption")]
|
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
|
||||||
pub async fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Sas> {
|
|
||||||
self.olm
|
|
||||||
.lock()
|
|
||||||
.await
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|o| o.get_verification(user_id, flow_id).map(|v| v.sas_v1()))
|
|
||||||
.flatten()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a specific device of a user.
|
/// Get a specific device of a user.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
|
|
@ -720,6 +720,7 @@ impl SledStore {
|
||||||
.map(|u| {
|
.map(|u| {
|
||||||
u.map_err(StoreError::Sled).and_then(|(key, value)| {
|
u.map_err(StoreError::Sled).and_then(|(key, value)| {
|
||||||
self.deserialize_event(&value)
|
self.deserialize_event(&value)
|
||||||
|
// TODO remove this unwrapping
|
||||||
.map(|receipt| {
|
.map(|receipt| {
|
||||||
(decode_key_value(&key, 3).unwrap().try_into().unwrap(), receipt)
|
(decode_key_value(&key, 3).unwrap().try_into().unwrap(), receipt)
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue