matrix_sdk/encryption/verification/
qrcode.rs

1// Copyright 2021 The Matrix.org Foundation C.I.C.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use futures_core::Stream;
16use matrix_sdk_base::crypto::{
17    matrix_sdk_qrcode::{qrcode::QrCode, EncodingError},
18    CancelInfo, DeviceData, QrVerification as BaseQrVerification, QrVerificationState,
19};
20use ruma::{RoomId, UserId};
21
22use crate::{Client, Result};
23
24/// An object controlling QR code style key verification flows.
25#[derive(Debug, Clone)]
26pub struct QrVerification {
27    pub(crate) inner: BaseQrVerification,
28    pub(crate) client: Client,
29}
30
31impl QrVerification {
32    /// Get our own user id.
33    pub fn own_user_id(&self) -> &UserId {
34        self.inner.user_id()
35    }
36
37    /// Is this a verification that is verifying one of our own devices.
38    pub fn is_self_verification(&self) -> bool {
39        self.inner.is_self_verification()
40    }
41
42    /// Has this verification finished.
43    pub fn is_done(&self) -> bool {
44        self.inner.is_done()
45    }
46
47    /// Whether the QrCode was scanned by the other device.
48    pub fn has_been_scanned(&self) -> bool {
49        self.inner.has_been_scanned()
50    }
51
52    /// Did we initiate the verification flow.
53    pub fn we_started(&self) -> bool {
54        self.inner.we_started()
55    }
56
57    /// Get info about the cancellation if the verification flow has been
58    /// cancelled.
59    pub fn cancel_info(&self) -> Option<CancelInfo> {
60        self.inner.cancel_info()
61    }
62
63    /// Get the user id of the other user participating in this verification
64    /// flow.
65    pub fn other_user_id(&self) -> &UserId {
66        self.inner.other_user_id()
67    }
68
69    /// Get the other user's device that we're verifying.
70    pub fn other_device(&self) -> &DeviceData {
71        self.inner.other_device()
72    }
73
74    /// Has the verification been cancelled.
75    pub fn is_cancelled(&self) -> bool {
76        self.inner.is_cancelled()
77    }
78
79    /// Generate a QR code object that is representing this verification flow.
80    ///
81    /// The `QrCode` can then be rendered as an image or as an unicode string.
82    ///
83    /// The [`to_bytes()`](#method.to_bytes) method can be used to instead
84    /// output the raw bytes that should be encoded as a QR code.
85    pub fn to_qr_code(&self) -> Result<QrCode, EncodingError> {
86        self.inner.to_qr_code()
87    }
88
89    /// Generate a the raw bytes that should be encoded as a QR code is
90    /// representing this verification flow.
91    ///
92    /// The [`to_qr_code()`](#method.to_qr_code) method can be used to instead
93    /// output a `QrCode` object that can be rendered.
94    pub fn to_bytes(&self) -> Result<Vec<u8>, EncodingError> {
95        self.inner.to_bytes()
96    }
97
98    /// Confirm that the other side has scanned our QR code.
99    pub async fn confirm(&self) -> Result<()> {
100        if let Some(request) = self.inner.confirm_scanning() {
101            self.client.send_verification_request(request).await?;
102        }
103
104        Ok(())
105    }
106
107    /// Abort the verification flow and notify the other side that we did so.
108    pub async fn cancel(&self) -> Result<()> {
109        if let Some(request) = self.inner.cancel() {
110            self.client.send_verification_request(request).await?;
111        }
112
113        Ok(())
114    }
115
116    /// Listen for changes in the QR code verification process.
117    ///
118    /// The changes are presented as a stream of [`QrVerificationState`] values.
119    ///
120    /// This method can be used to react to changes in the state of the
121    /// verification process, or rather the method can be used to handle
122    /// each step of the verification process.
123    ///
124    /// # Flowchart
125    ///
126    /// The flow of the verification process is pictured below. Please note
127    /// that the process can be cancelled at each step of the process.
128    /// Either side can cancel the process.
129    ///
130    /// ```text
131    ///                ┌───────┐
132    ///                │Started│
133    ///                └───┬───┘
134    ///                    │
135    ///                    │
136    ///             ┌──────⌄─────┐
137    ///             │Reciprocated│
138    ///             └──────┬─────┘
139    ///                    │
140    ///                ┌───⌄───┐
141    ///                │Scanned│
142    ///                └───┬───┘
143    ///                    │
144    ///          __________⌄_________
145    ///         ╱                    ╲       ┌─────────┐
146    ///        ╱   Was the QR Code    ╲______│Cancelled│
147    ///        ╲ successfully scanned ╱ no   └─────────┘
148    ///         ╲____________________╱
149    ///                    │yes
150    ///                    │
151    ///               ┌────⌄────┐
152    ///               │Confirmed│
153    ///               └────┬────┘
154    ///                    │
155    ///                ┌───⌄───┐
156    ///                │  Done │
157    ///                └───────┘
158    /// ```
159    /// # Examples
160    ///
161    /// ```no_run
162    /// use futures_util::{Stream, StreamExt};
163    /// use matrix_sdk::encryption::verification::{
164    ///     QrVerification, QrVerificationState,
165    /// };
166    ///
167    /// # async {
168    /// # let qr: QrVerification = unimplemented!();
169    /// # let user_confirmed = false;
170    /// let mut stream = qr.changes();
171    ///
172    /// while let Some(state) = stream.next().await {
173    ///     match state {
174    ///         QrVerificationState::Scanned => {
175    ///             println!("Was the QR code successfully scanned?");
176    ///
177    ///             // Ask the user to confirm or cancel here.
178    ///             if user_confirmed {
179    ///                 qr.confirm().await?;
180    ///             } else {
181    ///                 qr.cancel().await?;
182    ///             }
183    ///         }
184    ///         QrVerificationState::Done { .. } => {
185    ///             let device = qr.other_device();
186    ///
187    ///             println!(
188    ///                 "Successfully verified device {} {} {:?}",
189    ///                 device.user_id(),
190    ///                 device.device_id(),
191    ///                 device.local_trust_state()
192    ///             );
193    ///
194    ///             break;
195    ///         }
196    ///         QrVerificationState::Cancelled(cancel_info) => {
197    ///             println!(
198    ///                 "The verification has been cancelled, reason: {}",
199    ///                 cancel_info.reason()
200    ///             );
201    ///             break;
202    ///         }
203    ///         QrVerificationState::Started
204    ///         | QrVerificationState::Reciprocated
205    ///         | QrVerificationState::Confirmed => (),
206    ///     }
207    /// }
208    /// # anyhow::Ok(()) };
209    /// ```
210    pub fn changes(&self) -> impl Stream<Item = QrVerificationState> {
211        self.inner.changes()
212    }
213
214    /// Get the current state the verification process is in.
215    ///
216    /// To listen to changes to the [`QrVerificationState`] use the
217    /// [`QrVerification::changes`] method.
218    pub fn state(&self) -> QrVerificationState {
219        self.inner.state()
220    }
221
222    /// Get the room ID, if the verification is happening inside a room.
223    pub fn room_id(&self) -> Option<&RoomId> {
224        self.inner.room_id()
225    }
226}