crypto: Document all the new verification methods on the Rust side

This commit is contained in:
Damir Jelić 2021-07-23 11:50:34 +02:00
parent 52dd4bc454
commit 813b48df6a
7 changed files with 667 additions and 303 deletions

View File

@ -1,3 +1,5 @@
#![allow(missing_docs)]
use matrix_sdk_crypto::{
store::CryptoStoreError as InnerStoreError, KeyExportError, MegolmError, OlmError,
};

View File

@ -1,21 +1,43 @@
#![deny(
dead_code,
missing_docs,
trivial_casts,
trivial_numeric_casts,
unused_extern_crates,
unused_import_braces,
unused_qualifications
)]
//! TODO
mod device;
mod error;
mod logger;
mod machine;
mod responses;
mod verification;
pub use device::Device;
pub use error::{CryptoStoreError, DecryptionError, KeyImportError, MachineCreationError};
pub use logger::{set_logger, Logger};
pub use machine::{
CancelInfo, KeyRequestPair, OlmMachine, QrCode, RequestVerificationResult, Sas, ScanResult,
StartSasResult, Verification, VerificationRequest,
};
pub use machine::{KeyRequestPair, OlmMachine};
pub use responses::{
DeviceLists, KeysImportResult, OutgoingVerificationRequest, Request, RequestType,
};
pub use verification::{
CancelInfo, QrCode, RequestVerificationResult, Sas, ScanResult, StartSasResult, Verification,
VerificationRequest,
};
/// Callback that will be passed over the FFI to report progress
pub trait ProgressListener {
/// The callback that should be called on the Rust side
///
/// # Arguments
///
/// * `progress` - The current number of items that have been handled
///
/// * `total` - The total number of items that will be handled
fn on_progress(&self, progress: i32, total: i32);
}

View File

@ -4,8 +4,13 @@ use std::{
};
use tracing_subscriber::{fmt::MakeWriter, EnvFilter};
/// Trait that can be used to forward Rust logs over FFI to a language specific
/// logger.
pub trait Logger: Send {
/// Called every time the Rust side wants to post a log line.
fn log(&self, log_line: String);
// TODO add support for different log levels, do this by adding more methods
// to the trait.
}
impl Write for LoggerWrapper {
@ -34,6 +39,7 @@ pub struct LoggerWrapper {
inner: Arc<Mutex<Box<dyn Logger>>>,
}
/// Set the logger that should be used to forward Rust logs over FFI.
pub fn set_logger(logger: Box<dyn Logger>) {
let logger = LoggerWrapper {
inner: Arc::new(Mutex::new(logger)),

View File

@ -30,17 +30,16 @@ use tokio::runtime::Runtime;
use matrix_sdk_common::{deserialized_responses::AlgorithmInfo, uuid::Uuid};
use matrix_sdk_crypto::{
decrypt_key_export, encrypt_key_export, matrix_qrcode::QrVerificationData,
CancelInfo as RustCancelInfo, EncryptionSettings, LocalTrust, OlmMachine as InnerMachine,
QrVerification as InnerQr, Sas as InnerSas, Verification as RustVerification,
VerificationRequest as InnerVerificationRequest,
decrypt_key_export, encrypt_key_export, matrix_qrcode::QrVerificationData, EncryptionSettings,
LocalTrust, OlmMachine as InnerMachine, Verification as RustVerification,
};
use crate::{
error::{CryptoStoreError, DecryptionError, MachineCreationError},
responses::{response_from_string, OutgoingVerificationRequest, OwnedResponse},
DecryptedEvent, Device, DeviceLists, KeyImportError, KeysImportResult, ProgressListener,
Request, RequestType,
QrCode, Request, RequestType, RequestVerificationResult, ScanResult, StartSasResult,
Verification, VerificationRequest,
};
/// A high level state machine that handles E2EE for Matrix.
@ -49,148 +48,6 @@ pub struct OlmMachine {
runtime: Runtime,
}
pub enum Verification {
SasV1 { sas: Sas },
QrCodeV1 { qrcode: QrCode },
}
pub struct Sas {
pub other_user_id: String,
pub other_device_id: String,
pub flow_id: String,
pub room_id: Option<String>,
pub have_we_confirmed: bool,
pub is_cancelled: bool,
pub is_done: bool,
pub cancel_info: Option<CancelInfo>,
pub has_been_accepted: bool,
pub we_started: bool,
pub can_be_presented: bool,
pub supports_emoji: bool,
pub timed_out: bool,
}
pub struct QrCode {
pub other_user_id: String,
pub flow_id: String,
pub other_device_id: String,
pub room_id: Option<String>,
pub is_cancelled: bool,
pub is_done: bool,
pub we_started: bool,
pub other_side_scanned: bool,
pub has_been_confirmed: bool,
pub reciprocated: bool,
pub cancel_info: Option<CancelInfo>,
}
impl From<InnerQr> for QrCode {
fn from(qr: InnerQr) -> Self {
Self {
other_user_id: qr.other_user_id().to_string(),
flow_id: qr.flow_id().as_str().to_owned(),
is_cancelled: qr.is_cancelled(),
is_done: qr.is_done(),
cancel_info: qr.cancel_info().map(|c| c.into()),
reciprocated: qr.reciprocated(),
we_started: qr.we_started(),
other_side_scanned: qr.has_been_scanned(),
has_been_confirmed: qr.has_been_confirmed(),
other_device_id: qr.other_device_id().to_string(),
room_id: qr.room_id().map(|r| r.to_string()),
}
}
}
pub struct CancelInfo {
pub reason: String,
pub cancel_code: String,
pub cancelled_by_us: bool,
}
impl From<RustCancelInfo> for CancelInfo {
fn from(c: RustCancelInfo) -> Self {
Self {
reason: c.reason().to_owned(),
cancel_code: c.cancel_code().to_string(),
cancelled_by_us: c.cancelled_by_us(),
}
}
}
pub struct StartSasResult {
pub sas: Sas,
pub request: OutgoingVerificationRequest,
}
pub struct ScanResult {
pub qr: QrCode,
pub request: OutgoingVerificationRequest,
}
impl From<InnerSas> for Sas {
fn from(sas: InnerSas) -> Self {
Self {
other_user_id: sas.other_user_id().to_string(),
other_device_id: sas.other_device_id().to_string(),
flow_id: sas.flow_id().as_str().to_owned(),
is_cancelled: sas.is_cancelled(),
is_done: sas.is_done(),
can_be_presented: sas.can_be_presented(),
timed_out: sas.timed_out(),
supports_emoji: sas.supports_emoji(),
have_we_confirmed: sas.have_we_confirmed(),
we_started: sas.we_started(),
room_id: sas.room_id().map(|r| r.to_string()),
has_been_accepted: sas.has_been_accepted(),
cancel_info: sas.cancel_info().map(|c| c.into()),
}
}
}
pub struct RequestVerificationResult {
pub verification: VerificationRequest,
pub request: OutgoingVerificationRequest,
}
pub struct VerificationRequest {
pub other_user_id: String,
pub other_device_id: Option<String>,
pub flow_id: String,
pub is_cancelled: bool,
pub is_done: bool,
pub is_ready: bool,
pub room_id: Option<String>,
pub we_started: bool,
pub is_passive: bool,
pub their_methods: Option<Vec<String>>,
pub our_methods: Option<Vec<String>>,
pub cancel_info: Option<CancelInfo>,
}
impl From<InnerVerificationRequest> for VerificationRequest {
fn from(v: InnerVerificationRequest) -> Self {
Self {
other_user_id: v.other_user().to_string(),
other_device_id: v.other_device_id().map(|d| d.to_string()),
flow_id: v.flow_id().as_str().to_owned(),
is_cancelled: v.is_cancelled(),
is_done: v.is_done(),
is_ready: v.is_ready(),
room_id: v.room_id().map(|r| r.to_string()),
we_started: v.we_started(),
is_passive: v.is_passive(),
cancel_info: v.cancel_info().map(|c| c.into()),
their_methods: v
.their_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
our_methods: v
.our_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
}
}
}
/// A pair of outgoing room key requests, both of those are sendToDevice
/// requests.
pub struct KeyRequestPair {
@ -254,6 +111,7 @@ impl OlmMachine {
.map(|d| d.into()))
}
/// Mark the device of the given user with the given device id as trusted.
pub fn mark_device_as_trusted(
&self,
user_id: &str,
@ -696,6 +554,12 @@ impl OlmMachine {
Ok(())
}
/// Get all the verification requests that we share with the given user.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to fetch the
/// verification requests.
pub fn get_verification_requests(&self, user_id: &str) -> Vec<VerificationRequest> {
let user_id = if let Ok(user_id) = UserId::try_from(user_id) {
user_id
@ -710,6 +574,15 @@ impl OlmMachine {
.collect()
}
/// Get a verification requests that we share with the given user with the
/// given flow id.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to fetch the
/// verification requests.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn get_verification_request(
&self,
user_id: &str,
@ -722,6 +595,20 @@ impl OlmMachine {
.map(|v| v.into())
}
/// Accept a verification requests that we share with the given user with the
/// given flow id.
///
/// This will move the verification request into the ready state.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to accept the
/// verification requests.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
///
/// * `methods` - A list of verification methods that we want to advertise
/// as supported.
pub fn accept_verification_request(
&self,
user_id: &str,
@ -741,69 +628,59 @@ impl OlmMachine {
}
}
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Verification> {
let user_id = UserId::try_from(user_id).ok()?;
self.inner
.get_verification(&user_id, flow_id)
.map(|v| match v {
RustVerification::SasV1(s) => Verification::SasV1 { sas: s.into() },
RustVerification::QrV1(qr) => Verification::QrCodeV1 { qrcode: qr.into() },
})
}
pub fn start_qr_verification(
/// Get an m.key.verification.request content for the given user.
///
/// # Arguments
///
/// * `user_id` - The ID of the user which we would like to request to
/// verify.
///
/// * `methods` - The list of verification methods we want to advertise to
/// support.
pub fn verification_request_content(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<QrCode>, CryptoStoreError> {
methods: Vec<String>,
) -> Result<Option<String>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
Ok(self
let identity = self.runtime.block_on(self.inner.get_identity(&user_id))?;
let methods = methods
.into_iter()
.map(|m| VerificationMethod::from(m))
.collect();
Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
let content = self
.runtime
.block_on(verification.generate_qr_code())?
.map(|qr| qr.into()))
} else {
Ok(None)
}
}
pub fn generate_qr_code(&self, user_id: &str, flow_id: &str) -> Option<String> {
let user_id = UserId::try_from(user_id).ok()?;
self.inner
.get_verification(&user_id, flow_id)
.and_then(|v| {
v.qr_v1()
.and_then(|qr| qr.to_bytes().map(|b| encode(b)).ok())
})
}
pub fn scan_qr_code(&self, user_id: &str, flow_id: &str, data: &str) -> Option<ScanResult> {
let user_id = UserId::try_from(user_id).ok()?;
// TODO create a custom error type
let data = decode_config(data, STANDARD_NO_PAD).ok()?;
let data = QrVerificationData::from_bytes(data).ok()?;
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
if let Some(qr) = self
.runtime
.block_on(verification.scan_qr_code(data))
.ok()?
{
let request = qr.reciprocate()?;
Some(ScanResult {
qr: qr.into(),
request: request.into(),
})
} else {
None
}
.block_on(identity.verification_request_content(Some(methods)));
Some(serde_json::to_string(&content)?)
} else {
None
}
})
}
/// Request a verification flow to begin with the given user in the given
/// room.
///
/// # Arguments
///
/// * `user_id` - The ID of the user which we would like to request to
/// verify.
///
/// * `room_id` - The ID of the room that represents a DM with the given
/// user.
///
/// * `event_id` - The event ID of the `m.key.verification.request` event
/// that we sent out to request the verification to begin. The content for
/// this request can be created using the [verification_request_content()]
/// method.
///
/// * `methods` - The list of verification methods we advertised as
/// supported in the `m.key.verification.request` event.
///
/// [verification_request_content()]: #method.verification_request_content
pub fn request_verification(
&self,
user_id: &str,
@ -835,30 +712,55 @@ impl OlmMachine {
})
}
pub fn verification_request_content(
/// Request a verification flow to begin with the given user's device.
///
/// # Arguments
///
/// * `user_id` - The ID of the user which we would like to request to
/// verify.
///
/// * `device_id` - The ID of the device that we wish to verify.
///
/// * `methods` - The list of verification methods we advertised as
/// supported in the `m.key.verification.request` event.
pub fn request_verification_with_device(
&self,
user_id: &str,
device_id: &str,
methods: Vec<String>,
) -> Result<Option<String>, CryptoStoreError> {
) -> Result<Option<RequestVerificationResult>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
let identity = self.runtime.block_on(self.inner.get_identity(&user_id))?;
let methods = methods
.into_iter()
.map(|m| VerificationMethod::from(m))
.collect();
Ok(if let Some(identity) = identity.and_then(|i| i.other()) {
let content = self
Ok(
if let Some(device) = self
.runtime
.block_on(identity.verification_request_content(Some(methods)));
Some(serde_json::to_string(&content)?)
} else {
None
})
.block_on(self.inner.get_device(&user_id, device_id.into()))?
{
let (verification, request) = self
.runtime
.block_on(device.request_verification_with_methods(methods));
Some(RequestVerificationResult {
verification: verification.into(),
request: request.into(),
})
} else {
None
},
)
}
/// Request a verification flow to begin with our other devices.
///
/// # Arguments
///
/// `methods` - The list of verification methods we want to advertise to
/// support.
pub fn request_self_verification(
&self,
methods: Vec<String>,
@ -885,6 +787,239 @@ impl OlmMachine {
})
}
/// Get a verification flow object for the given user with the given flow id.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to fetch the
/// verification.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Verification> {
let user_id = UserId::try_from(user_id).ok()?;
self.inner
.get_verification(&user_id, flow_id)
.map(|v| match v {
RustVerification::SasV1(s) => Verification::SasV1 { sas: s.into() },
RustVerification::QrV1(qr) => Verification::QrCodeV1 { qrcode: qr.into() },
})
}
/// Cancel a verification for the given user with the given flow id using
/// the given cancel code.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to cancel the
/// verification.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
///
/// * `cancel_code` - The error code for why the verification was cancelled,
/// manual cancellatio usually happens with `m.user` cancel code. The full
/// list of cancel codes can be found in the [spec]
///
/// [spec]: https://spec.matrix.org/unstable/client-server-api/#mkeyverificationcancel
pub fn cancel_verification(
&self,
user_id: &str,
flow_id: &str,
cancel_code: &str,
) -> Option<OutgoingVerificationRequest> {
let user_id = UserId::try_from(user_id).ok()?;
if let Some(request) = self.inner.get_verification_request(&user_id, flow_id) {
request.cancel().map(|r| r.into())
} else if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
match verification {
RustVerification::SasV1(v) => {
v.cancel_with_code(cancel_code.into()).map(|r| r.into())
}
RustVerification::QrV1(v) => {
v.cancel_with_code(cancel_code.into()).map(|r| r.into())
}
}
} else {
None
}
}
/// Confirm a verification was successful.
///
/// This method should be called either if a short auth string should be
/// confirmed as matching, or if we want to confirm that the other side has
/// scanned our QR code.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to confirm the
/// verification.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn confirm_verification(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<OutgoingVerificationRequest>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
Ok(
if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
match verification {
RustVerification::SasV1(v) => {
self.runtime.block_on(v.confirm())?.0.map(|r| r.into())
}
RustVerification::QrV1(v) => v.confirm_scanning().map(|r| r.into()),
}
} else {
None
},
)
}
/// Transition from a verification request into QR code verification.
///
/// This method should be called when one wants to display a QR code so the
/// other side can scan it and move the QR code verification forward.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// QR code verification.
///
/// * `flow_id` - The ID of the verification request that initated the
/// verification flow.
pub fn start_qr_verification(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<QrCode>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
Ok(self
.runtime
.block_on(verification.generate_qr_code())?
.map(|qr| qr.into()))
} else {
Ok(None)
}
}
/// Generate data that should be encoded as a QR code.
///
/// This method should be called right before a QR code should be displayed,
/// the returned data is base64 encoded (without padding) and needs to be
/// decoded on the other side before it can be put through a QR code
/// generator.
///
/// *Note*: You'll need to call [start_qr_verification()] before calling this
/// method, otherwise `None` will be returned.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// QR code verification.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
///
/// [start_qr_verification()]: #method.start_qr_verification
pub fn generate_qr_code(&self, user_id: &str, flow_id: &str) -> Option<String> {
let user_id = UserId::try_from(user_id).ok()?;
self.inner
.get_verification(&user_id, flow_id)
.and_then(|v| {
v.qr_v1()
.and_then(|qr| qr.to_bytes().map(|b| encode(b)).ok())
})
}
/// Pass data from a scanned QR code to an active verification request and
/// transition into QR code verification.
///
/// This requires an active `VerificationRequest` to succeed, returns `None`
/// if no `VerificationRequest` is found or if the QR code data is invalid.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// QR code verification.
///
/// * `flow_id` - The ID of the verification request that initated the
/// verification flow.
///
/// * `data` - The data that was extracted from the scanned QR code as an
/// base64 encoded string, without padding.
pub fn scan_qr_code(&self, user_id: &str, flow_id: &str, data: &str) -> Option<ScanResult> {
let user_id = UserId::try_from(user_id).ok()?;
let data = decode_config(data, STANDARD_NO_PAD).ok()?;
let data = QrVerificationData::from_bytes(data).ok()?;
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
if let Some(qr) = self
.runtime
.block_on(verification.scan_qr_code(data))
.ok()?
{
let request = qr.reciprocate()?;
Some(ScanResult {
qr: qr.into(),
request: request.into(),
})
} else {
None
}
} else {
None
}
}
/// Transition from a verification request into short auth string based
/// verification.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// SAS verification.
///
/// * `flow_id` - The ID of the verification request that initated the
/// verification flow.
pub fn start_sas_verification(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<StartSasResult>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
Ok(
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
self.runtime
.block_on(verification.start_sas())?
.map(|(sas, r)| StartSasResult {
sas: sas.into(),
request: r.into(),
})
} else {
None
},
)
}
/// Start short auth string verification with a device without going
/// through a verification request first.
///
/// **Note**: This has been largely deprecated and the
/// [request_verification_with_device()] method should be used instead.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// SAS verification.
///
/// * `device_id` - The ID of device we would like to verify.
///
/// [request_verification_with_device()]: #method.request_verification_with_device
pub fn start_sas_with_device(
&self,
user_id: &str,
@ -909,27 +1044,14 @@ impl OlmMachine {
)
}
pub fn start_sas_verification(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<StartSasResult>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
Ok(
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
self.runtime
.block_on(verification.start_sas())?
.map(|(sas, r)| StartSasResult {
sas: sas.into(),
request: r.into(),
})
} else {
None
},
)
}
/// Accept that we're going forward with the short auth string verification.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to accept the
/// SAS verification.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn accept_sas_verification(
&self,
user_id: &str,
@ -942,49 +1064,19 @@ impl OlmMachine {
.and_then(|s| s.accept().map(|r| r.into()))
}
pub fn cancel_verification(
&self,
user_id: &str,
flow_id: &str,
cancel_code: &str,
) -> Option<OutgoingVerificationRequest> {
let user_id = UserId::try_from(user_id).ok()?;
if let Some(request) = self.inner.get_verification_request(&user_id, flow_id) {
request.cancel().map(|r| r.into())
} else if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
match verification {
RustVerification::SasV1(v) => {
v.cancel_with_code(cancel_code.into()).map(|r| r.into())
}
RustVerification::QrV1(v) => v.cancel().map(|r| r.into()),
}
} else {
None
}
}
pub fn confirm_verification(
&self,
user_id: &str,
flow_id: &str,
) -> Result<Option<OutgoingVerificationRequest>, CryptoStoreError> {
let user_id = UserId::try_from(user_id)?;
Ok(
if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
match verification {
RustVerification::SasV1(v) => {
self.runtime.block_on(v.confirm())?.0.map(|r| r.into())
}
RustVerification::QrV1(v) => v.confirm_scanning().map(|r| r.into()),
}
} else {
None
},
)
}
/// Get a list of emoji indices of the emoji representation of the short
/// auth string.
///
/// *Note*: A SAS verification needs to be started and in the presentable
/// state for this to return the list of emoji indices, otherwise returns
/// `None`.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to get the
/// short auth string.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn get_emoji_index(&self, user_id: &str, flow_id: &str) -> Option<Vec<i32>> {
let user_id = UserId::try_from(user_id).ok()?;
@ -998,6 +1090,18 @@ impl OlmMachine {
})
}
/// Get the decimal representation of the short auth string.
///
/// *Note*: A SAS verification needs to be started and in the presentable
/// state for this to return the list of decimals, otherwise returns
/// `None`.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to get the
/// short auth string.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
pub fn get_decimals(&self, user_id: &str, flow_id: &str) -> Option<Vec<i32>> {
let user_id = UserId::try_from(user_id).ok()?;

View File

@ -83,12 +83,11 @@ dictionary Sas {
string? room_id;
boolean we_started;
boolean has_been_accepted;
boolean can_be_presented;
boolean supports_emoji;
boolean have_we_confirmed;
boolean is_done;
boolean is_cancelled;
boolean can_be_presented;
boolean timed_out;
boolean supports_emoji;
CancelInfo? cancel_info;
};
@ -97,18 +96,17 @@ dictionary ScanResult {
OutgoingVerificationRequest request;
};
dictionary QrCode {
string other_user_id;
string other_device_id;
string flow_id;
string? room_id;
boolean reciprocated;
boolean we_started;
boolean other_side_scanned;
boolean has_been_confirmed;
boolean reciprocated;
boolean is_done;
boolean is_cancelled;
boolean other_side_scanned;
CancelInfo? cancel_info;
};
@ -116,12 +114,12 @@ dictionary VerificationRequest {
string other_user_id;
string? other_device_id;
string flow_id;
boolean is_cancelled;
boolean is_done;
boolean is_ready;
boolean we_started;
boolean is_passive;
string? room_id;
boolean we_started;
boolean is_ready;
boolean is_passive;
boolean is_done;
boolean is_cancelled;
CancelInfo? cancel_info;
sequence<string>? their_methods;
sequence<string>? our_methods;
@ -209,12 +207,6 @@ interface OlmMachine {
VerificationRequest? get_verification_request([ByRef] string user_id, [ByRef] string flow_id);
Verification? get_verification([ByRef] string user_id, [ByRef] string flow_id);
OutgoingVerificationRequest? accept_verification_request(
[ByRef] string user_id,
[ByRef] string flow_id,
sequence<string> methods
);
[Throws=CryptoStoreError]
VerificationRequest? request_verification(
[ByRef] string user_id,
@ -230,9 +222,18 @@ interface OlmMachine {
[Throws=CryptoStoreError]
RequestVerificationResult? request_self_verification(sequence<string> methods);
[Throws=CryptoStoreError]
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
[Throws=CryptoStoreError]
StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
RequestVerificationResult? request_verification_with_device(
[ByRef] string user_id,
[ByRef] string device_id,
sequence<string> methods
);
OutgoingVerificationRequest? accept_verification_request(
[ByRef] string user_id,
[ByRef] string flow_id,
sequence<string> methods
);
[Throws=CryptoStoreError]
OutgoingVerificationRequest? confirm_verification([ByRef] string user_id, [ByRef] string flow_id);
OutgoingVerificationRequest? cancel_verification(
@ -240,15 +241,20 @@ interface OlmMachine {
[ByRef] string flow_id,
[ByRef] string cancel_code
);
[Throws=CryptoStoreError]
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
[Throws=CryptoStoreError]
StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
OutgoingVerificationRequest? accept_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_emoji_index([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_decimals([ByRef] string user_id, [ByRef] string flow_id);
[Throws=CryptoStoreError]
QrCode? start_qr_verification([ByRef] string user_id, [ByRef] string flow_id);
ScanResult? scan_qr_code([ByRef] string user_id, [ByRef] string flow_id, [ByRef] string data);
string? generate_qr_code([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_emoji_index([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_decimals([ByRef] string user_id, [ByRef] string flow_id);
[Throws=DecryptionError]
KeyRequestPair request_room_key([ByRef] string event, [ByRef] string room_id);

View File

@ -1,3 +1,5 @@
#![allow(missing_docs)]
use std::{collections::HashMap, convert::TryFrom};
use http::Response;

View File

@ -0,0 +1,222 @@
use matrix_sdk_crypto::{
CancelInfo as RustCancelInfo, QrVerification as InnerQr, Sas as InnerSas,
VerificationRequest as InnerVerificationRequest,
};
use crate::OutgoingVerificationRequest;
/// Enum representing the different verification flows we support.
pub enum Verification {
/// The `m.sas.v1` verification flow.
SasV1 {
#[allow(missing_docs)]
sas: Sas
},
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
/// verification flow.
QrCodeV1 {
#[allow(missing_docs)]
qrcode: QrCode
},
}
/// The `m.sas.v1` verification flow.
pub struct Sas {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: String,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Has the non-initiating side accepted the verification flow
pub has_been_accepted: bool,
/// Can the short auth string be presented
pub can_be_presented: bool,
/// Does the flow support the emoji representation of the short auth string
pub supports_emoji: bool,
/// Have we confirmed that the short auth strings match
pub have_we_confirmed: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
}
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
/// verification flow.
pub struct QrCode {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: String,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Has the QR code been scanned by the other side
pub other_side_scanned: bool,
/// Has the scanning of the QR code been confirmed by us
pub has_been_confirmed: bool,
/// Did we scan the QR code and sent out a reciprocation
pub reciprocated: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
}
impl From<InnerQr> for QrCode {
fn from(qr: InnerQr) -> Self {
Self {
other_user_id: qr.other_user_id().to_string(),
flow_id: qr.flow_id().as_str().to_owned(),
is_cancelled: qr.is_cancelled(),
is_done: qr.is_done(),
cancel_info: qr.cancel_info().map(|c| c.into()),
reciprocated: qr.reciprocated(),
we_started: qr.we_started(),
other_side_scanned: qr.has_been_scanned(),
has_been_confirmed: qr.has_been_confirmed(),
other_device_id: qr.other_device_id().to_string(),
room_id: qr.room_id().map(|r| r.to_string()),
}
}
}
/// Information on why a verification flow has been cancelled and by whom.
pub struct CancelInfo {
/// The textual representation of the cancel reason
pub reason: String,
/// The code describing the cancel reason
pub cancel_code: String,
/// Was the verification flow cancelled by us
pub cancelled_by_us: bool,
}
impl From<RustCancelInfo> for CancelInfo {
fn from(c: RustCancelInfo) -> Self {
Self {
reason: c.reason().to_owned(),
cancel_code: c.cancel_code().to_string(),
cancelled_by_us: c.cancelled_by_us(),
}
}
}
/// A result type for starting SAS verifications.
pub struct StartSasResult {
/// The SAS verification object that got created.
pub sas: Sas,
/// The request that needs to be sent out to notify the other side that a
/// SAS verification should start.
pub request: OutgoingVerificationRequest,
}
/// A result type for scanning QR codes.
pub struct ScanResult {
/// The QR code verification object that got created.
pub qr: QrCode,
/// The request that needs to be sent out to notify the other side that a
/// QR code verification should start.
pub request: OutgoingVerificationRequest,
}
impl From<InnerSas> for Sas {
fn from(sas: InnerSas) -> Self {
Self {
other_user_id: sas.other_user_id().to_string(),
other_device_id: sas.other_device_id().to_string(),
flow_id: sas.flow_id().as_str().to_owned(),
is_cancelled: sas.is_cancelled(),
is_done: sas.is_done(),
can_be_presented: sas.can_be_presented(),
supports_emoji: sas.supports_emoji(),
have_we_confirmed: sas.have_we_confirmed(),
we_started: sas.we_started(),
room_id: sas.room_id().map(|r| r.to_string()),
has_been_accepted: sas.has_been_accepted(),
cancel_info: sas.cancel_info().map(|c| c.into()),
}
}
}
/// A result type for requesting verifications.
pub struct RequestVerificationResult {
/// The verification request object that got created.
pub verification: VerificationRequest,
/// The request that needs to be sent out to notify the other side that
/// we're requesting verification to begin.
pub request: OutgoingVerificationRequest,
}
/// The verificatoin request object which then can transition into some concrete
/// verification method
pub struct VerificationRequest {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: Option<String>,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Did both parties aggree to verification
pub is_ready: bool,
/// Did another device respond to the verification request
pub is_passive: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// The list of verification methods that the other side advertised as
/// supported
pub their_methods: Option<Vec<String>>,
/// The list of verification methods that we advertised as supported
pub our_methods: Option<Vec<String>>,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
}
impl From<InnerVerificationRequest> for VerificationRequest {
fn from(v: InnerVerificationRequest) -> Self {
Self {
other_user_id: v.other_user().to_string(),
other_device_id: v.other_device_id().map(|d| d.to_string()),
flow_id: v.flow_id().as_str().to_owned(),
is_cancelled: v.is_cancelled(),
is_done: v.is_done(),
is_ready: v.is_ready(),
room_id: v.room_id().map(|r| r.to_string()),
we_started: v.we_started(),
is_passive: v.is_passive(),
cancel_info: v.cancel_info().map(|c| c.into()),
their_methods: v
.their_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
our_methods: v
.our_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
}
}
}