mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-14 11:05:32 -04:00
refactor!(bindings): Return objects for the verification support
When the verification support was initially bound, Uniffi did not support objects (the OlmMachine) returning other objects (our verification objects). Instead we converted all the verification objects into pure data structs which the other side had to poll for changes. Now that Uniffi supports returning objects we can refactor this and make the API on the other side the same as on the Rust side.
This commit is contained in:
@@ -6,7 +6,6 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use base64::{decode_config, encode, STANDARD_NO_PAD};
|
||||
use js_int::UInt;
|
||||
use matrix_sdk_common::deserialized_responses::AlgorithmInfo;
|
||||
use matrix_sdk_crypto::{
|
||||
@@ -15,10 +14,9 @@ use matrix_sdk_crypto::{
|
||||
SignatureVerification as RustSignatureCheckResult,
|
||||
},
|
||||
decrypt_room_key_export, encrypt_room_key_export,
|
||||
matrix_sdk_qrcode::QrVerificationData,
|
||||
olm::ExportedRoomKey,
|
||||
store::RecoveryKey,
|
||||
LocalTrust, OlmMachine as InnerMachine, UserIdentities, Verification as RustVerification,
|
||||
LocalTrust, OlmMachine as InnerMachine, UserIdentities,
|
||||
};
|
||||
use ruma::{
|
||||
api::{
|
||||
@@ -48,12 +46,12 @@ use zeroize::Zeroize;
|
||||
use crate::{
|
||||
error::{CryptoStoreError, DecryptionError, SecretImportError, SignatureError},
|
||||
parse_user_id,
|
||||
responses::{response_from_string, OutgoingVerificationRequest, OwnedResponse},
|
||||
BackupKeys, BackupRecoveryKey, BootstrapCrossSigningResult, ConfirmVerificationResult,
|
||||
CrossSigningKeyExport, CrossSigningStatus, DecodeError, DecryptedEvent, Device, DeviceLists,
|
||||
EncryptionSettings, KeyImportError, KeysImportResult, MegolmV1BackupKey, ProgressListener,
|
||||
QrCode, Request, RequestType, RequestVerificationResult, RoomKeyCounts, ScanResult,
|
||||
SignatureUploadRequest, StartSasResult, UserIdentity, Verification, VerificationRequest,
|
||||
responses::{response_from_string, OwnedResponse},
|
||||
BackupKeys, BackupRecoveryKey, BootstrapCrossSigningResult, CrossSigningKeyExport,
|
||||
CrossSigningStatus, DecodeError, DecryptedEvent, Device, DeviceLists, EncryptionSettings,
|
||||
KeyImportError, KeysImportResult, MegolmV1BackupKey, ProgressListener, Request, RequestType,
|
||||
RequestVerificationResult, RoomKeyCounts, Sas, SignatureUploadRequest, StartSasResult,
|
||||
UserIdentity, Verification, VerificationRequest,
|
||||
};
|
||||
|
||||
/// A high level state machine that handles E2EE for Matrix.
|
||||
@@ -842,12 +840,18 @@ impl OlmMachine {
|
||||
///
|
||||
/// * `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> {
|
||||
pub fn get_verification_requests(&self, user_id: &str) -> Vec<Arc<VerificationRequest>> {
|
||||
let Ok(user_id) = UserId::parse(user_id) else {
|
||||
return vec![];
|
||||
};
|
||||
|
||||
self.inner.get_verification_requests(&user_id).into_iter().map(|v| v.into()).collect()
|
||||
self.inner
|
||||
.get_verification_requests(&user_id)
|
||||
.into_iter()
|
||||
.map(|v| {
|
||||
VerificationRequest { inner: v, runtime: self.runtime.handle().to_owned() }.into()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get a verification requests that we share with the given user with the
|
||||
@@ -863,40 +867,12 @@ impl OlmMachine {
|
||||
&self,
|
||||
user_id: &str,
|
||||
flow_id: &str,
|
||||
) -> Option<VerificationRequest> {
|
||||
) -> Option<Arc<VerificationRequest>> {
|
||||
let user_id = UserId::parse(user_id).ok()?;
|
||||
|
||||
self.inner.get_verification_request(&user_id, flow_id).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,
|
||||
flow_id: &str,
|
||||
methods: Vec<String>,
|
||||
) -> Option<OutgoingVerificationRequest> {
|
||||
let user_id = UserId::parse(user_id).ok()?;
|
||||
let methods = methods.into_iter().map(VerificationMethod::from).collect();
|
||||
|
||||
if let Some(verification) = self.inner.get_verification_request(&user_id, flow_id) {
|
||||
verification.accept_with_methods(methods).map(|r| r.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
self.inner.get_verification_request(&user_id, flow_id).map(|v| {
|
||||
VerificationRequest { inner: v, runtime: self.runtime.handle().to_owned() }.into()
|
||||
})
|
||||
}
|
||||
|
||||
/// Get an m.key.verification.request content for the given user.
|
||||
@@ -954,7 +930,7 @@ impl OlmMachine {
|
||||
room_id: &str,
|
||||
event_id: &str,
|
||||
methods: Vec<String>,
|
||||
) -> Result<Option<VerificationRequest>, CryptoStoreError> {
|
||||
) -> Result<Option<Arc<VerificationRequest>>, CryptoStoreError> {
|
||||
let user_id = parse_user_id(user_id)?;
|
||||
let event_id = EventId::parse(event_id)?;
|
||||
let room_id = RoomId::parse(room_id)?;
|
||||
@@ -970,7 +946,10 @@ impl OlmMachine {
|
||||
Some(methods),
|
||||
));
|
||||
|
||||
Some(request.into())
|
||||
Some(
|
||||
VerificationRequest { inner: request, runtime: self.runtime.handle().to_owned() }
|
||||
.into(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
@@ -1005,7 +984,11 @@ impl OlmMachine {
|
||||
self.runtime.block_on(device.request_verification_with_methods(methods));
|
||||
|
||||
Some(RequestVerificationResult {
|
||||
verification: verification.into(),
|
||||
verification: VerificationRequest {
|
||||
inner: verification,
|
||||
runtime: self.runtime.handle().to_owned(),
|
||||
}
|
||||
.into(),
|
||||
request: request.into(),
|
||||
})
|
||||
} else {
|
||||
@@ -1033,7 +1016,11 @@ impl OlmMachine {
|
||||
let (verification, request) =
|
||||
self.runtime.block_on(identity.request_verification_with_methods(methods))?;
|
||||
Some(RequestVerificationResult {
|
||||
verification: verification.into(),
|
||||
verification: VerificationRequest {
|
||||
inner: verification,
|
||||
runtime: self.runtime.handle().to_owned(),
|
||||
}
|
||||
.into(),
|
||||
request: request.into(),
|
||||
})
|
||||
} else {
|
||||
@@ -1050,206 +1037,12 @@ impl OlmMachine {
|
||||
/// verification.
|
||||
///
|
||||
/// * `flow_id` - The ID that uniquely identifies the verification flow.
|
||||
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Verification> {
|
||||
pub fn get_verification(&self, user_id: &str, flow_id: &str) -> Option<Arc<Verification>> {
|
||||
let user_id = UserId::parse(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() },
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
|
||||
/// 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::parse(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())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} 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<ConfirmVerificationResult>, CryptoStoreError> {
|
||||
let user_id = parse_user_id(user_id)?;
|
||||
|
||||
Ok(if let Some(verification) = self.inner.get_verification(&user_id, flow_id) {
|
||||
match verification {
|
||||
RustVerification::SasV1(v) => {
|
||||
let (requests, signature_request) = self.runtime.block_on(v.confirm())?;
|
||||
|
||||
let requests = requests.into_iter().map(|r| r.into()).collect();
|
||||
|
||||
Some(ConfirmVerificationResult {
|
||||
requests,
|
||||
signature_request: signature_request.map(|s| s.into()),
|
||||
})
|
||||
}
|
||||
RustVerification::QrV1(v) => v.confirm_scanning().map(|r| {
|
||||
ConfirmVerificationResult { requests: vec![r.into()], signature_request: None }
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} 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 initiated the
|
||||
/// verification flow.
|
||||
pub fn start_qr_verification(
|
||||
&self,
|
||||
user_id: &str,
|
||||
flow_id: &str,
|
||||
) -> Result<Option<QrCode>, CryptoStoreError> {
|
||||
let user_id = parse_user_id(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::parse(user_id).ok()?;
|
||||
self.inner
|
||||
.get_verification(&user_id, flow_id)
|
||||
.and_then(|v| v.qr_v1().and_then(|qr| qr.to_bytes().map(encode).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 initiated 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::parse(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 initiated the
|
||||
/// verification flow.
|
||||
pub fn start_sas_verification(
|
||||
&self,
|
||||
user_id: &str,
|
||||
flow_id: &str,
|
||||
) -> Result<Option<StartSasResult>, CryptoStoreError> {
|
||||
let user_id = parse_user_id(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
|
||||
})
|
||||
.map(|v| Verification { inner: v, runtime: self.runtime.handle().to_owned() }.into())
|
||||
}
|
||||
|
||||
/// Start short auth string verification with a device without going
|
||||
@@ -1279,74 +1072,16 @@ impl OlmMachine {
|
||||
{
|
||||
let (sas, request) = self.runtime.block_on(device.start_verification())?;
|
||||
|
||||
Some(StartSasResult { sas: sas.into(), request: request.into() })
|
||||
Some(StartSasResult {
|
||||
sas: Sas { inner: sas, runtime: self.runtime.handle().to_owned() }.into(),
|
||||
request: request.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,
|
||||
flow_id: &str,
|
||||
) -> Option<OutgoingVerificationRequest> {
|
||||
let user_id = UserId::parse(user_id).ok()?;
|
||||
|
||||
self.inner.get_verification(&user_id, flow_id)?.sas_v1()?.accept().map(|r| r.into())
|
||||
}
|
||||
|
||||
/// 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::parse(user_id).ok()?;
|
||||
|
||||
self.inner.get_verification(&user_id, flow_id).and_then(|s| {
|
||||
s.sas_v1()
|
||||
.and_then(|s| s.emoji_index().map(|v| v.iter().map(|i| (*i).into()).collect()))
|
||||
})
|
||||
}
|
||||
|
||||
/// 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::parse(user_id).ok()?;
|
||||
|
||||
self.inner.get_verification(&user_id, flow_id).and_then(|s| {
|
||||
s.sas_v1()
|
||||
.and_then(|s| s.decimals().map(|v| [v.0.into(), v.1.into(), v.2.into()].to_vec()))
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a new private cross signing identity and create a request to
|
||||
/// upload the public part of it to the server.
|
||||
pub fn bootstrap_cross_signing(&self) -> Result<BootstrapCrossSigningResult, CryptoStoreError> {
|
||||
|
||||
@@ -146,19 +146,21 @@ dictionary StartSasResult {
|
||||
OutgoingVerificationRequest request;
|
||||
};
|
||||
|
||||
dictionary Sas {
|
||||
string other_user_id;
|
||||
string other_device_id;
|
||||
string flow_id;
|
||||
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;
|
||||
CancelInfo? cancel_info;
|
||||
interface Sas {
|
||||
string other_user_id();
|
||||
string other_device_id();
|
||||
string flow_id();
|
||||
string? room_id();
|
||||
boolean we_started();
|
||||
boolean is_done();
|
||||
|
||||
OutgoingVerificationRequest? accept();
|
||||
[Throws=CryptoStoreError]
|
||||
ConfirmVerificationResult? confirm();
|
||||
OutgoingVerificationRequest? cancel([ByRef] string cancel_code);
|
||||
|
||||
sequence<i32>? get_emoji_indices();
|
||||
sequence<i32>? get_decimals();
|
||||
};
|
||||
|
||||
dictionary ScanResult {
|
||||
@@ -166,34 +168,44 @@ dictionary ScanResult {
|
||||
OutgoingVerificationRequest request;
|
||||
};
|
||||
|
||||
dictionary QrCode {
|
||||
string other_user_id;
|
||||
string other_device_id;
|
||||
string flow_id;
|
||||
string? room_id;
|
||||
boolean we_started;
|
||||
boolean other_side_scanned;
|
||||
boolean has_been_confirmed;
|
||||
boolean reciprocated;
|
||||
boolean is_done;
|
||||
boolean is_cancelled;
|
||||
CancelInfo? cancel_info;
|
||||
interface QrCode {
|
||||
string other_user_id();
|
||||
string other_device_id();
|
||||
string flow_id();
|
||||
string? room_id();
|
||||
boolean we_started();
|
||||
boolean is_done();
|
||||
CancelInfo? cancel_info();
|
||||
|
||||
boolean reciprocated();
|
||||
boolean has_been_scanned();
|
||||
|
||||
ConfirmVerificationResult? confirm();
|
||||
OutgoingVerificationRequest? cancel([ByRef] string cancel_code);
|
||||
string? generate_qr_code();
|
||||
};
|
||||
|
||||
dictionary VerificationRequest {
|
||||
string other_user_id;
|
||||
string? other_device_id;
|
||||
string flow_id;
|
||||
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;
|
||||
interface VerificationRequest {
|
||||
string other_user_id();
|
||||
string? other_device_id();
|
||||
string flow_id();
|
||||
string? room_id();
|
||||
boolean we_started();
|
||||
boolean is_ready();
|
||||
boolean is_done();
|
||||
boolean is_passive();
|
||||
|
||||
sequence<string>? their_supported_methods();
|
||||
sequence<string>? our_supported_methods();
|
||||
|
||||
OutgoingVerificationRequest? accept(sequence<string> methods);
|
||||
|
||||
[Throws=CryptoStoreError]
|
||||
StartSasResult? start_sas_verification();
|
||||
|
||||
[Throws=CryptoStoreError]
|
||||
QrCode? start_qr_verification();
|
||||
ScanResult? scan_qr_code([ByRef] string data);
|
||||
};
|
||||
|
||||
dictionary RequestVerificationResult {
|
||||
@@ -206,10 +218,9 @@ dictionary ConfirmVerificationResult {
|
||||
SignatureUploadRequest? signature_request;
|
||||
};
|
||||
|
||||
[Enum]
|
||||
interface Verification {
|
||||
SasV1(Sas sas);
|
||||
QrCodeV1(QrCode qrcode);
|
||||
QrCode? as_qr();
|
||||
Sas? as_sas();
|
||||
};
|
||||
|
||||
dictionary KeyRequestPair {
|
||||
@@ -361,32 +372,8 @@ interface OlmMachine {
|
||||
sequence<string> methods
|
||||
);
|
||||
|
||||
OutgoingVerificationRequest? accept_verification_request(
|
||||
[ByRef] string user_id,
|
||||
[ByRef] string flow_id,
|
||||
sequence<string> methods
|
||||
);
|
||||
|
||||
[Throws=CryptoStoreError]
|
||||
ConfirmVerificationResult? confirm_verification([ByRef] string user_id, [ByRef] string flow_id);
|
||||
OutgoingVerificationRequest? cancel_verification(
|
||||
[ByRef] string user_id,
|
||||
[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);
|
||||
|
||||
[Throws=DecryptionError]
|
||||
KeyRequestPair request_room_key([ByRef] string event, [ByRef] string room_id);
|
||||
|
||||
@@ -1,101 +1,224 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use base64::{decode_config, encode_config, STANDARD_NO_PAD};
|
||||
use matrix_sdk_crypto::{
|
||||
CancelInfo as RustCancelInfo, QrVerification as InnerQr, Sas as InnerSas,
|
||||
matrix_sdk_qrcode::QrVerificationData, CancelInfo as RustCancelInfo, QrVerification as InnerQr,
|
||||
Sas as InnerSas, Verification as InnerVerification,
|
||||
VerificationRequest as InnerVerificationRequest,
|
||||
};
|
||||
use ruma::events::key::verification::VerificationMethod;
|
||||
use tokio::runtime::Handle;
|
||||
|
||||
use crate::{OutgoingVerificationRequest, SignatureUploadRequest};
|
||||
use crate::{CryptoStoreError, OutgoingVerificationRequest, SignatureUploadRequest};
|
||||
|
||||
/// 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,
|
||||
},
|
||||
pub struct Verification {
|
||||
pub(crate) inner: InnerVerification,
|
||||
pub(crate) runtime: Handle,
|
||||
}
|
||||
|
||||
impl Verification {
|
||||
/// Try to represent the `Verification` as an `Sas` verification object,
|
||||
/// returns `None` if the verification is not a `Sas` verification.
|
||||
pub fn as_sas(&self) -> Option<Arc<Sas>> {
|
||||
if let InnerVerification::SasV1(sas) = &self.inner {
|
||||
Some(Sas { inner: sas.to_owned(), runtime: self.runtime.to_owned() }.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Try to represent the `Verification` as an `QrCode` verification object,
|
||||
/// returns `None` if the verification is not a `QrCode` verification.
|
||||
pub fn as_qr(&self) -> Option<Arc<QrCode>> {
|
||||
if let InnerVerification::QrV1(qr) = &self.inner {
|
||||
Some(QrCode { inner: qr.to_owned() }.into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
pub(crate) inner: InnerSas,
|
||||
pub(crate) runtime: Handle,
|
||||
}
|
||||
|
||||
impl Sas {
|
||||
/// Get the user id of the other side.
|
||||
pub fn other_user_id(&self) -> String {
|
||||
self.inner.other_user_id().to_string()
|
||||
}
|
||||
|
||||
/// Get the device ID of the other side.
|
||||
pub fn other_device_id(&self) -> String {
|
||||
self.inner.other_device_id().to_string()
|
||||
}
|
||||
|
||||
/// Get the unique ID that identifies this SAS verification flow.
|
||||
pub fn flow_id(&self) -> String {
|
||||
self.inner.flow_id().as_str().to_owned()
|
||||
}
|
||||
|
||||
/// Get the room id if the verification is happening inside a room.
|
||||
pub fn room_id(&self) -> Option<String> {
|
||||
self.inner.room_id().map(|r| r.to_string())
|
||||
}
|
||||
|
||||
/// Is the SAS flow done.
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.inner.is_done()
|
||||
}
|
||||
|
||||
/// Did we initiate the verification flow.
|
||||
pub fn we_started(&self) -> bool {
|
||||
self.inner.we_started()
|
||||
}
|
||||
|
||||
/// Accept that we're going forward with the short auth string verification.
|
||||
pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.accept().map(|r| r.into())
|
||||
}
|
||||
|
||||
/// Confirm a verification was successful.
|
||||
///
|
||||
/// This method should be called if a short auth string should be confirmed
|
||||
/// as matching.
|
||||
pub fn confirm(&self) -> Result<Option<ConfirmVerificationResult>, CryptoStoreError> {
|
||||
let (requests, signature_request) = self.runtime.block_on(self.inner.confirm())?;
|
||||
|
||||
let requests = requests.into_iter().map(|r| r.into()).collect();
|
||||
|
||||
Ok(Some(ConfirmVerificationResult {
|
||||
requests,
|
||||
signature_request: signature_request.map(|s| s.into()),
|
||||
}))
|
||||
}
|
||||
|
||||
/// Cancel the SAS verification using the given cancel code.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `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(&self, cancel_code: &str) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
pub fn get_emoji_indices(&self) -> Option<Vec<i32>> {
|
||||
self.inner.emoji_index().map(|v| v.iter().map(|i| (*i).into()).collect())
|
||||
}
|
||||
|
||||
/// 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`.
|
||||
pub fn get_decimals(&self) -> Option<Vec<i32>> {
|
||||
self.inner.decimals().map(|v| [v.0.into(), v.1.into(), v.2.into()].to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
/// 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>,
|
||||
pub(crate) inner: InnerQr,
|
||||
}
|
||||
|
||||
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()),
|
||||
}
|
||||
impl QrCode {
|
||||
/// Get the user id of the other side.
|
||||
pub fn other_user_id(&self) -> String {
|
||||
self.inner.other_user_id().to_string()
|
||||
}
|
||||
|
||||
/// Get the device ID of the other side.
|
||||
pub fn other_device_id(&self) -> String {
|
||||
self.inner.other_device_id().to_string()
|
||||
}
|
||||
|
||||
/// Get the unique ID that identifies this QR code verification flow.
|
||||
pub fn flow_id(&self) -> String {
|
||||
self.inner.flow_id().as_str().to_owned()
|
||||
}
|
||||
|
||||
/// Get the room id if the verification is happening inside a room.
|
||||
pub fn room_id(&self) -> Option<String> {
|
||||
self.inner.room_id().map(|r| r.to_string())
|
||||
}
|
||||
|
||||
/// Is the QR code verification done.
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.inner.is_done()
|
||||
}
|
||||
|
||||
/// Did we initiate the verification flow.
|
||||
pub fn we_started(&self) -> bool {
|
||||
self.inner.we_started()
|
||||
}
|
||||
|
||||
/// Get the CancelInfo of this QR code verification object.
|
||||
///
|
||||
/// Will be `None` if the flow has not been cancelled.
|
||||
pub fn cancel_info(&self) -> Option<CancelInfo> {
|
||||
self.inner.cancel_info().map(|c| c.into())
|
||||
}
|
||||
|
||||
/// Has the QR verification been scanned by the other side.
|
||||
///
|
||||
/// When the verification object is in this state it's required that the
|
||||
/// user confirms that the other side has scanned the QR code.
|
||||
pub fn has_been_scanned(&self) -> bool {
|
||||
self.inner.has_been_scanned()
|
||||
}
|
||||
|
||||
/// Have we successfully scanned the QR code and are able to send a
|
||||
/// reciprocation event.
|
||||
pub fn reciprocated(&self) -> bool {
|
||||
self.inner.reciprocated()
|
||||
}
|
||||
|
||||
/// Cancel the QR code verification using the given cancel code.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `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(&self, cancel_code: &str) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
|
||||
}
|
||||
|
||||
/// Confirm a verification was successful.
|
||||
///
|
||||
/// This method should be called if we want to confirm that the other side
|
||||
/// has scanned our QR code.
|
||||
pub fn confirm(&self) -> Option<ConfirmVerificationResult> {
|
||||
self.inner.confirm_scanning().map(|r| ConfirmVerificationResult {
|
||||
requests: vec![r.into()],
|
||||
signature_request: 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.
|
||||
pub fn generate_qr_code(&self) -> Option<String> {
|
||||
self.inner.to_bytes().map(|data| encode_config(data, STANDARD_NO_PAD)).ok()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +245,7 @@ impl From<RustCancelInfo> for CancelInfo {
|
||||
/// A result type for starting SAS verifications.
|
||||
pub struct StartSasResult {
|
||||
/// The SAS verification object that got created.
|
||||
pub sas: Sas,
|
||||
pub sas: Arc<Sas>,
|
||||
/// The request that needs to be sent out to notify the other side that a
|
||||
/// SAS verification should start.
|
||||
pub request: OutgoingVerificationRequest,
|
||||
@@ -131,35 +254,16 @@ pub struct StartSasResult {
|
||||
/// A result type for scanning QR codes.
|
||||
pub struct ScanResult {
|
||||
/// The QR code verification object that got created.
|
||||
pub qr: QrCode,
|
||||
pub qr: Arc<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,
|
||||
pub verification: Arc<VerificationRequest>,
|
||||
/// The request that needs to be sent out to notify the other side that
|
||||
/// we're requesting verification to begin.
|
||||
pub request: OutgoingVerificationRequest,
|
||||
@@ -178,55 +282,155 @@ pub struct ConfirmVerificationResult {
|
||||
/// 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>,
|
||||
pub(crate) inner: InnerVerificationRequest,
|
||||
pub(crate) runtime: Handle,
|
||||
}
|
||||
|
||||
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()),
|
||||
impl VerificationRequest {
|
||||
/// The id of the other user that is participating in this verification
|
||||
/// request.
|
||||
pub fn other_user_id(&self) -> String {
|
||||
self.inner.other_user().to_string()
|
||||
}
|
||||
|
||||
/// The id of the other device that is participating in this verification.
|
||||
pub fn other_device_id(&self) -> Option<String> {
|
||||
self.inner.other_device_id().map(|d| d.to_string())
|
||||
}
|
||||
|
||||
/// Get the unique ID of this verification request
|
||||
pub fn flow_id(&self) -> String {
|
||||
self.inner.flow_id().as_str().to_owned()
|
||||
}
|
||||
|
||||
/// Get the room id if the verification is happening inside a room.
|
||||
pub fn room_id(&self) -> Option<String> {
|
||||
self.inner.room_id().map(|r| r.to_string())
|
||||
}
|
||||
|
||||
/// Has the verification flow that was started with this request finished.
|
||||
pub fn is_done(&self) -> bool {
|
||||
self.inner.is_done()
|
||||
}
|
||||
|
||||
/// Is the verification request ready to start a verification flow.
|
||||
pub fn is_ready(&self) -> bool {
|
||||
self.inner.is_ready()
|
||||
}
|
||||
|
||||
/// Did we initiate the verification request
|
||||
pub fn we_started(&self) -> bool {
|
||||
self.inner.we_started()
|
||||
}
|
||||
|
||||
/// Has the verification request been answered by another device.
|
||||
pub fn is_passive(&self) -> bool {
|
||||
self.inner.is_passive()
|
||||
}
|
||||
|
||||
/// 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<String>> {
|
||||
self.inner.their_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
|
||||
}
|
||||
|
||||
/// Get our own supported verification methods that we advertised.
|
||||
///
|
||||
/// Will be present only we requested the verification or if we're in the
|
||||
/// ready state.
|
||||
pub fn our_supported_methods(&self) -> Option<Vec<String>> {
|
||||
self.inner.our_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
|
||||
}
|
||||
|
||||
/// 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(&self, methods: Vec<String>) -> Option<OutgoingVerificationRequest> {
|
||||
let methods = methods.into_iter().map(VerificationMethod::from).collect();
|
||||
self.inner.accept_with_methods(methods).map(|r| r.into())
|
||||
}
|
||||
|
||||
/// Cancel a verification for the given user with the given flow id using
|
||||
/// the given cancel code.
|
||||
pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
|
||||
self.inner.cancel().map(|r| r.into())
|
||||
}
|
||||
|
||||
/// 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 initiated the
|
||||
/// verification flow.
|
||||
pub fn start_sas_verification(&self) -> Result<Option<StartSasResult>, CryptoStoreError> {
|
||||
Ok(self.runtime.block_on(self.inner.start_sas())?.map(|(sas, r)| StartSasResult {
|
||||
sas: Arc::new(Sas { inner: sas, runtime: self.runtime.clone() }),
|
||||
request: r.into(),
|
||||
}))
|
||||
}
|
||||
|
||||
/// 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 initiated the
|
||||
/// verification flow.
|
||||
pub fn start_qr_verification(&self) -> Result<Option<Arc<QrCode>>, CryptoStoreError> {
|
||||
Ok(self
|
||||
.runtime
|
||||
.block_on(self.inner.generate_qr_code())?
|
||||
.map(|qr| QrCode { inner: qr }.into()))
|
||||
}
|
||||
|
||||
/// 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 initiated 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, data: &str) -> Option<ScanResult> {
|
||||
let data = decode_config(data, STANDARD_NO_PAD).ok()?;
|
||||
let data = QrVerificationData::from_bytes(data).ok()?;
|
||||
|
||||
if let Some(qr) = self.runtime.block_on(self.inner.scan_qr_code(data)).ok()? {
|
||||
let request = qr.reciprocate()?;
|
||||
|
||||
Some(ScanResult { qr: QrCode { inner: qr }.into(), request: request.into() })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user