matrix_sdk_crypto/verification/
requests.rs

1// Copyright 2020 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 std::{ops::Add, sync::Arc, time::Duration};
16
17use as_variant::as_variant;
18use eyeball::{ObservableWriteGuard, SharedObservable, WeakObservable};
19use futures_core::Stream;
20use futures_util::StreamExt;
21#[cfg(feature = "qrcode")]
22use matrix_sdk_qrcode::QrVerificationData;
23use ruma::{
24    events::{
25        key::verification::{
26            cancel::CancelCode,
27            ready::{KeyVerificationReadyEventContent, ToDeviceKeyVerificationReadyEventContent},
28            request::ToDeviceKeyVerificationRequestEventContent,
29            start::StartMethod,
30            VerificationMethod,
31        },
32        relation::Reference,
33        room::message::KeyVerificationRequestEventContent,
34        AnyMessageLikeEventContent, AnyToDeviceEventContent,
35    },
36    time::Instant,
37    to_device::DeviceIdOrAllDevices,
38    DeviceId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, RoomId, TransactionId,
39    UserId,
40};
41#[cfg(feature = "qrcode")]
42use tracing::debug;
43use tracing::{info, trace, warn};
44
45#[cfg(feature = "qrcode")]
46use super::qrcode::{QrVerification, QrVerificationState, ScanError};
47use super::{
48    cache::VerificationCache,
49    event_enums::{
50        CancelContent, DoneContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
51    },
52    CancelInfo, Cancelled, FlowId, Verification, VerificationStore,
53};
54use crate::{
55    olm::StaticAccountData,
56    types::requests::{OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest},
57    CryptoStoreError, DeviceData, Sas,
58};
59
60const SUPPORTED_METHODS: &[VerificationMethod] = &[
61    VerificationMethod::SasV1,
62    #[cfg(feature = "qrcode")]
63    VerificationMethod::QrCodeShowV1,
64    VerificationMethod::ReciprocateV1,
65];
66
67const VERIFICATION_TIMEOUT: Duration = Duration::from_secs(60 * 10);
68
69/// An Enum describing the state the verification request is in.
70#[derive(Debug, Clone)]
71pub enum VerificationRequestState {
72    /// The verification request has been newly created by us.
73    Created {
74        /// The verification methods supported by us.
75        our_methods: Vec<VerificationMethod>,
76    },
77    /// The verification request was received from the other party.
78    Requested {
79        /// The verification methods supported by the sender.
80        their_methods: Vec<VerificationMethod>,
81
82        /// The device data of the device that responded to the verification
83        /// request.
84        other_device_data: DeviceData,
85    },
86    /// The verification request is ready to start a verification flow.
87    Ready {
88        /// The verification methods supported by the other side.
89        their_methods: Vec<VerificationMethod>,
90
91        /// The verification methods supported by the us.
92        our_methods: Vec<VerificationMethod>,
93
94        /// The device data of the device that responded to the verification
95        /// request.
96        other_device_data: DeviceData,
97    },
98    /// The verification request has transitioned into a concrete verification
99    /// flow. For example it transitioned into the emoji based SAS
100    /// verification.
101    Transitioned {
102        /// The concrete [`Verification`] object the verification request
103        /// transitioned into.
104        verification: Verification,
105
106        /// The device data of the device that responded to the verification
107        /// request.
108        other_device_data: DeviceData,
109    },
110    /// The verification flow that was started with this request has finished.
111    Done,
112    /// The verification process has been cancelled.
113    Cancelled(CancelInfo),
114}
115
116impl From<&InnerRequest> for VerificationRequestState {
117    fn from(value: &InnerRequest) -> Self {
118        match value {
119            InnerRequest::Created(s) => {
120                Self::Created { our_methods: s.state.our_methods.to_owned() }
121            }
122            InnerRequest::Requested(s) => Self::Requested {
123                their_methods: s.state.their_methods.to_owned(),
124                other_device_data: s.state.other_device_data.to_owned(),
125            },
126            InnerRequest::Ready(s) => Self::Ready {
127                their_methods: s.state.their_methods.to_owned(),
128                our_methods: s.state.our_methods.to_owned(),
129                other_device_data: s.state.other_device_data.to_owned(),
130            },
131            InnerRequest::Transitioned(s) => Self::Transitioned {
132                verification: s.state.verification.to_owned(),
133                other_device_data: s.state.other_device_data.to_owned(),
134            },
135            InnerRequest::Passive(_) => {
136                Self::Cancelled(Cancelled::new(true, CancelCode::Accepted).into())
137            }
138            InnerRequest::Done(_) => Self::Done,
139            InnerRequest::Cancelled(s) => Self::Cancelled(s.state.to_owned().into()),
140        }
141    }
142}
143
144/// An object controlling key verification requests.
145///
146/// Interactive verification flows usually start with a verification request,
147/// this object lets you send and reply to such a verification request.
148///
149/// After the initial handshake the verification flow transitions into one of
150/// the verification methods.
151#[derive(Clone, Debug)]
152pub struct VerificationRequest {
153    verification_cache: VerificationCache,
154    account: StaticAccountData,
155    flow_id: Arc<FlowId>,
156    other_user_id: OwnedUserId,
157    inner: SharedObservable<InnerRequest>,
158    creation_time: Arc<Instant>,
159    we_started: bool,
160    recipient_devices: Arc<Vec<OwnedDeviceId>>,
161}
162
163/// A handle to a request so child verification flows can cancel the request.
164///
165/// A verification flow can branch off into different types of verification
166/// flows after the initial request handshake is done.
167///
168/// Cancelling a QR code verification should also cancel the request. This
169/// `RequestHandle` allows the QR code verification object to cancel the parent
170/// `VerificationRequest` object.
171#[derive(Debug, Clone)]
172pub(crate) struct RequestHandle {
173    inner: WeakObservable<InnerRequest>,
174}
175
176impl RequestHandle {
177    pub fn cancel_with_code(&self, cancel_code: &CancelCode) {
178        if let Some(observable) = self.inner.upgrade() {
179            let mut guard = observable.write();
180
181            if let Some(updated) = guard.cancel(true, cancel_code) {
182                ObservableWriteGuard::set(&mut guard, updated);
183            }
184        }
185    }
186}
187
188impl From<SharedObservable<InnerRequest>> for RequestHandle {
189    fn from(inner: SharedObservable<InnerRequest>) -> Self {
190        let inner = inner.downgrade();
191
192        Self { inner }
193    }
194}
195
196impl VerificationRequest {
197    pub(crate) fn new(
198        cache: VerificationCache,
199        store: VerificationStore,
200        flow_id: FlowId,
201        other_user: &UserId,
202        recipient_devices: Vec<OwnedDeviceId>,
203        methods: Option<Vec<VerificationMethod>>,
204    ) -> Self {
205        let account = store.account.clone();
206        let inner = SharedObservable::new(InnerRequest::Created(RequestState::new(
207            cache.clone(),
208            store,
209            other_user,
210            &flow_id,
211            methods,
212        )));
213
214        Self {
215            account,
216            verification_cache: cache,
217            flow_id: flow_id.into(),
218            inner,
219            other_user_id: other_user.into(),
220            creation_time: Instant::now().into(),
221            we_started: true,
222            recipient_devices: recipient_devices.into(),
223        }
224    }
225
226    /// Create an event content that can be sent as a to-device event to request
227    /// verification from the other side. This should be used only for
228    /// self-verifications and it should be sent to the specific device that we
229    /// want to verify.
230    pub(crate) fn request_to_device(&self) -> ToDeviceRequest {
231        let inner = self.inner.read();
232
233        let methods = if let InnerRequest::Created(c) = &*inner {
234            c.state.our_methods.clone()
235        } else {
236            SUPPORTED_METHODS.to_vec()
237        };
238
239        let content = ToDeviceKeyVerificationRequestEventContent::new(
240            self.account.device_id.clone(),
241            self.flow_id().as_str().into(),
242            methods,
243            MilliSecondsSinceUnixEpoch::now(),
244        );
245
246        ToDeviceRequest::for_recipients(
247            self.other_user(),
248            self.recipient_devices.to_vec(),
249            &AnyToDeviceEventContent::KeyVerificationRequest(content),
250            TransactionId::new(),
251        )
252    }
253
254    /// Create an event content that can be sent as a room event to request
255    /// verification from the other side. This should be used only for
256    /// verifications of other users and it should be sent to a room we consider
257    /// to be a DM with the other user.
258    pub fn request(
259        own_user_id: &UserId,
260        own_device_id: &DeviceId,
261        other_user_id: &UserId,
262        methods: Option<Vec<VerificationMethod>>,
263    ) -> KeyVerificationRequestEventContent {
264        KeyVerificationRequestEventContent::new(
265            format!(
266                "{own_user_id} is requesting to verify your key, but your client does not \
267                support in-chat key verification. You will need to use legacy \
268                key verification to verify keys."
269            ),
270            methods.unwrap_or_else(|| SUPPORTED_METHODS.to_vec()),
271            own_device_id.into(),
272            other_user_id.to_owned(),
273        )
274    }
275
276    /// Our own user id.
277    pub fn own_user_id(&self) -> &UserId {
278        &self.account.user_id
279    }
280
281    /// The id of the other user that is participating in this verification
282    /// request.
283    pub fn other_user(&self) -> &UserId {
284        &self.other_user_id
285    }
286
287    /// The id of the other device that is participating in this verification.
288    pub fn other_device_id(&self) -> Option<OwnedDeviceId> {
289        match &*self.inner.read() {
290            InnerRequest::Requested(r) => Some(r.state.other_device_data.device_id().to_owned()),
291            InnerRequest::Ready(r) => Some(r.state.other_device_data.device_id().to_owned()),
292            InnerRequest::Transitioned(r) => {
293                Some(r.state.ready.other_device_data.device_id().to_owned())
294            }
295            InnerRequest::Created(_)
296            | InnerRequest::Passive(_)
297            | InnerRequest::Done(_)
298            | InnerRequest::Cancelled(_) => None,
299        }
300    }
301
302    /// Get the room id if the verification is happening inside a room.
303    pub fn room_id(&self) -> Option<&RoomId> {
304        match self.flow_id.as_ref() {
305            FlowId::ToDevice(_) => None,
306            FlowId::InRoom(r, _) => Some(r),
307        }
308    }
309
310    /// Get info about the cancellation if the verification request has been
311    /// cancelled.
312    pub fn cancel_info(&self) -> Option<CancelInfo> {
313        as_variant!(&*self.inner.read(), InnerRequest::Cancelled(c) => {
314            c.state.clone().into()
315        })
316    }
317
318    /// Has the verification request been answered by another device.
319    pub fn is_passive(&self) -> bool {
320        matches!(*self.inner.read(), InnerRequest::Passive(_))
321    }
322
323    /// Is the verification request ready to start a verification flow.
324    pub fn is_ready(&self) -> bool {
325        matches!(*self.inner.read(), InnerRequest::Ready(_))
326    }
327
328    /// Has the verification flow timed out.
329    pub fn timed_out(&self) -> bool {
330        self.creation_time.elapsed() > VERIFICATION_TIMEOUT
331    }
332
333    /// Get the time left before the verification flow will time out, without
334    /// further action.
335    pub fn time_remaining(&self) -> Duration {
336        self.creation_time
337            .add(VERIFICATION_TIMEOUT)
338            .checked_duration_since(Instant::now())
339            .unwrap_or(Duration::from_secs(0))
340    }
341
342    /// Get the supported verification methods of the other side.
343    ///
344    /// Will be present only if the other side requested the verification or if
345    /// we're in the ready state.
346    pub fn their_supported_methods(&self) -> Option<Vec<VerificationMethod>> {
347        match &*self.inner.read() {
348            InnerRequest::Requested(r) => Some(r.state.their_methods.clone()),
349            InnerRequest::Ready(r) => Some(r.state.their_methods.clone()),
350            InnerRequest::Transitioned(r) => Some(r.state.ready.their_methods.clone()),
351            InnerRequest::Created(_)
352            | InnerRequest::Passive(_)
353            | InnerRequest::Done(_)
354            | InnerRequest::Cancelled(_) => None,
355        }
356    }
357
358    /// Get our own supported verification methods that we advertised.
359    ///
360    /// Will be present only we requested the verification or if we're in the
361    /// ready state.
362    pub fn our_supported_methods(&self) -> Option<Vec<VerificationMethod>> {
363        match &*self.inner.read() {
364            InnerRequest::Created(r) => Some(r.state.our_methods.clone()),
365            InnerRequest::Ready(r) => Some(r.state.our_methods.clone()),
366            InnerRequest::Transitioned(r) => Some(r.state.ready.our_methods.clone()),
367            InnerRequest::Requested(_)
368            | InnerRequest::Passive(_)
369            | InnerRequest::Done(_)
370            | InnerRequest::Cancelled(_) => None,
371        }
372    }
373
374    /// Get the unique ID of this verification request
375    pub fn flow_id(&self) -> &FlowId {
376        &self.flow_id
377    }
378
379    /// Is this a verification that is verifying one of our own devices
380    pub fn is_self_verification(&self) -> bool {
381        self.account.user_id == self.other_user()
382    }
383
384    /// Did we initiate the verification request
385    pub fn we_started(&self) -> bool {
386        self.we_started
387    }
388
389    /// Has the verification flow that was started with this request finished.
390    pub fn is_done(&self) -> bool {
391        matches!(*self.inner.read(), InnerRequest::Done(_))
392    }
393
394    /// Has the verification flow that was started with this request been
395    /// cancelled.
396    pub fn is_cancelled(&self) -> bool {
397        matches!(*self.inner.read(), InnerRequest::Cancelled(_))
398    }
399
400    /// Generate a QR code that can be used by another client to start a QR code
401    /// based verification.
402    #[cfg(feature = "qrcode")]
403    pub async fn generate_qr_code(&self) -> Result<Option<QrVerification>, CryptoStoreError> {
404        let inner = self.inner.get();
405
406        let ret = if let Some((state, verification)) =
407            inner.generate_qr_code(self.we_started, self.inner.clone().into()).await?
408        {
409            let mut inner = self.inner.write();
410            ObservableWriteGuard::set(&mut inner, InnerRequest::Transitioned(state));
411
412            Some(verification)
413        } else {
414            None
415        };
416
417        Ok(ret)
418    }
419
420    /// Start a QR code verification by providing a scanned QR code for this
421    /// verification flow.
422    ///
423    /// Returns a `ScanError` if the QR code isn't valid, `None` if the
424    /// verification request isn't in the ready state or we don't support QR
425    /// code verification, otherwise a newly created `QrVerification` object
426    /// which will be used for the remainder of the verification flow.
427    #[cfg(feature = "qrcode")]
428    pub async fn scan_qr_code(
429        &self,
430        data: QrVerificationData,
431    ) -> Result<Option<QrVerification>, ScanError> {
432        let inner = self.inner.read().to_owned();
433
434        let (new_state, qr_verification) = match inner {
435            InnerRequest::Ready(r) => {
436                scan_qr_code(data, &r, &r.state, self.we_started, self.inner.to_owned().into())
437                    .await?
438            }
439            InnerRequest::Transitioned(r) => {
440                scan_qr_code(
441                    data,
442                    &r,
443                    &r.state.ready,
444                    self.we_started,
445                    self.inner.to_owned().into(),
446                )
447                .await?
448            }
449            _ => return Ok(None),
450        };
451
452        // We may have previously started our own QR verification (e.g. two devices
453        // displaying QR code at the same time), so we need to replace it with the newly
454        // scanned code.
455        if self
456            .verification_cache
457            .get_qr(qr_verification.other_user_id(), qr_verification.flow_id().as_str())
458            .is_some()
459        {
460            self.verification_cache.replace_qr(qr_verification.clone());
461        } else {
462            self.verification_cache.insert_qr(qr_verification.clone());
463        }
464
465        let mut guard = self.inner.write();
466        ObservableWriteGuard::set(&mut guard, InnerRequest::Transitioned(new_state));
467
468        Ok(Some(qr_verification))
469    }
470
471    pub(crate) fn from_request(
472        cache: VerificationCache,
473        store: VerificationStore,
474        sender: &UserId,
475        flow_id: FlowId,
476        content: &RequestContent<'_>,
477        device_data: DeviceData,
478    ) -> Self {
479        let account = store.account.clone();
480
481        Self {
482            verification_cache: cache.clone(),
483            inner: SharedObservable::new(InnerRequest::Requested(
484                RequestState::from_request_event(
485                    cache,
486                    store,
487                    sender,
488                    &flow_id,
489                    content,
490                    device_data,
491                ),
492            )),
493            account,
494            other_user_id: sender.into(),
495            flow_id: flow_id.into(),
496            we_started: false,
497            creation_time: Instant::now().into(),
498            recipient_devices: vec![].into(),
499        }
500    }
501
502    /// Accept the verification request signaling that our client supports the
503    /// given verification methods.
504    ///
505    /// # Arguments
506    ///
507    /// * `methods` - The methods that we should advertise as supported by us.
508    pub fn accept_with_methods(
509        &self,
510        methods: Vec<VerificationMethod>,
511    ) -> Option<OutgoingVerificationRequest> {
512        let mut guard = self.inner.write();
513        let (updated, content) = guard.accept(methods)?;
514
515        ObservableWriteGuard::set(&mut guard, updated);
516
517        let request = match content {
518            OutgoingContent::ToDevice(content) => ToDeviceRequest::with_id(
519                self.other_user(),
520                guard.other_device_id(),
521                &content,
522                TransactionId::new(),
523            )
524            .into(),
525            OutgoingContent::Room(room_id, content) => {
526                RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
527            }
528        };
529
530        Some(request)
531    }
532
533    /// Accept the verification request.
534    ///
535    /// This method will accept the request and signal that it supports the
536    /// `m.sas.v1`, the `m.qr_code.show.v1`, and `m.reciprocate.v1` method.
537    ///
538    /// `m.qr_code.show.v1` will only be signaled if the `qrcode` feature is
539    /// enabled. This feature is disabled by default. If it's enabled and QR
540    /// code scanning should be supported or QR code showing shouldn't be
541    /// supported the [`accept_with_methods()`] method should be used
542    /// instead.
543    ///
544    /// [`accept_with_methods()`]: #method.accept_with_methods
545    pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
546        self.accept_with_methods(SUPPORTED_METHODS.to_vec())
547    }
548
549    /// Cancel the verification request
550    pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
551        self.cancel_with_code(CancelCode::User)
552    }
553
554    fn cancel_with_code(&self, cancel_code: CancelCode) -> Option<OutgoingVerificationRequest> {
555        let mut guard = self.inner.write();
556
557        let send_to_everyone = self.we_started() && matches!(*guard, InnerRequest::Created(_));
558        let other_device = guard.other_device_id();
559
560        if let Some(updated) = guard.cancel(true, &cancel_code) {
561            ObservableWriteGuard::set(&mut guard, updated);
562        }
563
564        let content = as_variant!(&*guard, InnerRequest::Cancelled(c) => {
565            c.state.as_content(self.flow_id())
566        });
567
568        let request = content.map(|c| match c {
569            OutgoingContent::ToDevice(content) => {
570                if send_to_everyone {
571                    ToDeviceRequest::for_recipients(
572                        self.other_user(),
573                        self.recipient_devices.to_vec(),
574                        &content,
575                        TransactionId::new(),
576                    )
577                    .into()
578                } else {
579                    ToDeviceRequest::with_id(
580                        self.other_user(),
581                        other_device,
582                        &content,
583                        TransactionId::new(),
584                    )
585                    .into()
586                }
587            }
588            OutgoingContent::Room(room_id, content) => {
589                RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
590            }
591        });
592
593        drop(guard);
594
595        if let Some(verification) =
596            self.verification_cache.get(self.other_user(), self.flow_id().as_str())
597        {
598            match verification {
599                Verification::SasV1(s) => s.cancel_with_code(cancel_code),
600                #[cfg(feature = "qrcode")]
601                Verification::QrV1(q) => q.cancel_with_code(cancel_code),
602            };
603        }
604
605        request
606    }
607
608    pub(crate) fn cancel_if_timed_out(&self) -> Option<OutgoingVerificationRequest> {
609        if self.is_cancelled() || self.is_done() {
610            None
611        } else if self.timed_out() {
612            let request = self.cancel_with_code(CancelCode::Timeout);
613
614            if self.is_passive() {
615                None
616            } else {
617                trace!(
618                    other_user = self.other_user().as_str(),
619                    flow_id = self.flow_id().as_str(),
620                    "Timing a verification request out"
621                );
622                request
623            }
624        } else {
625            None
626        }
627    }
628
629    /// Create a key verification cancellation for devices that received the
630    /// request but either shouldn't continue in the verification or didn't get
631    /// notified that the other side cancelled.
632    ///
633    /// The spec states the following[1]:
634    /// When Bob accepts or declines the verification on one of his devices
635    /// (sending either an m.key.verification.ready or m.key.verification.cancel
636    /// event), Alice will send an m.key.verification.cancel event to Bob’s
637    /// other devices with a code of m.accepted in the case where Bob accepted
638    /// the verification, or m.user in the case where Bob rejected the
639    /// verification.
640    ///
641    /// Realistically sending the cancellation to Bob's other devices is only
642    /// possible if Bob accepted the verification since we don't know the device
643    /// id of Bob's device that rejected the verification.
644    ///
645    /// Thus, we're sending the cancellation to all devices that received the
646    /// request in the rejection case.
647    ///
648    /// [1]: https://spec.matrix.org/unstable/client-server-api/#key-verification-framework
649    pub(crate) fn cancel_for_other_devices(
650        &self,
651        code: CancelCode,
652        filter_device: Option<&DeviceId>,
653    ) -> Option<ToDeviceRequest> {
654        let cancelled = Cancelled::new(true, code);
655        let cancel_content = cancelled.as_content(self.flow_id());
656
657        let OutgoingContent::ToDevice(c) = cancel_content else { return None };
658        let recip_devices: Vec<OwnedDeviceId> = self
659            .recipient_devices
660            .iter()
661            .filter(|&d| filter_device.is_none_or(|device| **d != *device))
662            .cloned()
663            .collect();
664
665        if recip_devices.is_empty() && filter_device.is_some() {
666            // We don't need to notify anyone if no recipients were present but
667            // we did have a filter device, since this means that only a single
668            // device received the `m.key.verification.request` and that device
669            // accepted the request.
670            return None;
671        }
672
673        let recipient = self.other_user();
674        Some(ToDeviceRequest::for_recipients(recipient, recip_devices, &c, TransactionId::new()))
675    }
676
677    pub(crate) fn receive_ready(
678        &self,
679        sender: &UserId,
680        content: &ReadyContent<'_>,
681        from_device_data: DeviceData,
682    ) {
683        let mut guard = self.inner.write();
684
685        match &*guard {
686            InnerRequest::Created(s) => {
687                let new_value =
688                    InnerRequest::Ready(s.clone().into_ready(sender, content, from_device_data));
689                ObservableWriteGuard::set(&mut guard, new_value);
690
691                if let Some(request) =
692                    self.cancel_for_other_devices(CancelCode::Accepted, Some(content.from_device()))
693                {
694                    self.verification_cache.add_verification_request(request.into());
695                }
696            }
697            InnerRequest::Requested(s) => {
698                if sender == self.own_user_id() && content.from_device() != self.account.device_id {
699                    let new_value = InnerRequest::Passive(s.clone().into_passive(content));
700                    ObservableWriteGuard::set(&mut guard, new_value);
701                }
702            }
703            InnerRequest::Ready(_)
704            | InnerRequest::Transitioned(_)
705            | InnerRequest::Passive(_)
706            | InnerRequest::Done(_)
707            | InnerRequest::Cancelled(_) => {}
708        }
709    }
710
711    pub(crate) async fn receive_start(
712        &self,
713        sender: &UserId,
714        content: &StartContent<'_>,
715    ) -> Result<(), CryptoStoreError> {
716        let inner = self.inner.get();
717
718        match &inner {
719            InnerRequest::Created(_)
720            | InnerRequest::Requested(_)
721            | InnerRequest::Passive(_)
722            | InnerRequest::Done(_)
723            | InnerRequest::Cancelled(_) => {
724                warn!(
725                    ?sender,
726                    device_id = content.from_device().as_str(),
727                    "Received a key verification start event but we're not yet in the ready state"
728                );
729                Ok(())
730            }
731            InnerRequest::Ready(s) => {
732                let s = s.clone();
733
734                if let Some(new_state) = s
735                    .receive_start(sender, content, self.we_started, self.inner.clone().into())
736                    .await?
737                {
738                    let mut inner = self.inner.write();
739                    ObservableWriteGuard::set(&mut inner, InnerRequest::Transitioned(new_state));
740                }
741
742                Ok(())
743            }
744            InnerRequest::Transitioned(s) => {
745                // This is the same as the `Ready` state. We need to support this in the case
746                // someone tries QR code verification and notices that they can't scan the QR
747                // code for one reason or the other, in that case they are able
748                // to transition into the emoji based SAS verification.
749                //
750                // In this case we're going to from one `Transitioned` state into another.
751                let s = s.clone();
752
753                if let Some(new_state) = s
754                    .receive_start(sender, content, self.we_started, self.inner.clone().into())
755                    .await?
756                {
757                    let mut inner = self.inner.write();
758                    ObservableWriteGuard::set(&mut inner, InnerRequest::Transitioned(new_state));
759                }
760
761                Ok(())
762            }
763        }
764    }
765
766    pub(crate) fn receive_done(&self, sender: &UserId, content: &DoneContent<'_>) {
767        if sender == self.other_user() {
768            trace!(
769                other_user = ?self.other_user(),
770                flow_id = self.flow_id().as_str(),
771                "Marking a verification request as done"
772            );
773
774            let mut guard = self.inner.write();
775            if let Some(updated) = guard.receive_done(content) {
776                ObservableWriteGuard::set(&mut guard, updated);
777            }
778        }
779    }
780
781    pub(crate) fn receive_cancel(&self, sender: &UserId, content: &CancelContent<'_>) {
782        if sender != self.other_user() {
783            return;
784        }
785
786        trace!(
787            ?sender,
788            code = content.cancel_code().as_str(),
789            "Cancelling a verification request, other user has cancelled"
790        );
791        let mut guard = self.inner.write();
792        if let Some(updated) = guard.cancel(false, content.cancel_code()) {
793            ObservableWriteGuard::set(&mut guard, updated);
794        }
795
796        if self.we_started() {
797            if let Some(request) =
798                self.cancel_for_other_devices(content.cancel_code().to_owned(), None)
799            {
800                self.verification_cache.add_verification_request(request.into());
801            }
802        }
803    }
804
805    fn start_sas_helper(
806        &self,
807        new_state: RequestState<Transitioned>,
808        sas: Sas,
809        content: OutgoingContent,
810        other_device_id: DeviceIdOrAllDevices,
811    ) -> Option<(Sas, OutgoingVerificationRequest)> {
812        // We may have previously started QR verification and generated a QR code. If we
813        // now switch to SAS flow, the previous verification has to be replaced
814        cfg_if::cfg_if! {
815            if #[cfg(feature = "qrcode")] {
816                if self.verification_cache.get_qr(sas.other_user_id(), sas.flow_id().as_str()).is_some() {
817                    debug!(
818                        user_id = ?self.other_user(),
819                        flow_id = self.flow_id().as_str(),
820                        "We have an ongoing QR verification, replacing with SAS"
821                    );
822                    self.verification_cache.replace(sas.clone().into())
823                } else {
824                    self.verification_cache.insert_sas(sas.clone());
825                }
826            } else {
827                self.verification_cache.insert_sas(sas.clone());
828            }
829        }
830
831        let request = match content {
832            OutgoingContent::ToDevice(content) => ToDeviceRequest::with_id(
833                self.other_user(),
834                other_device_id,
835                &content,
836                TransactionId::new(),
837            )
838            .into(),
839            OutgoingContent::Room(room_id, content) => {
840                RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
841            }
842        };
843
844        let mut guard = self.inner.write();
845        ObservableWriteGuard::set(&mut guard, InnerRequest::Transitioned(new_state));
846
847        Some((sas, request))
848    }
849
850    /// Transition from this verification request into a SAS verification flow.
851    pub async fn start_sas(
852        &self,
853    ) -> Result<Option<(Sas, OutgoingVerificationRequest)>, CryptoStoreError> {
854        let inner = self.inner.get();
855        let other_device_id = inner.other_device_id();
856
857        Ok(match &inner {
858            InnerRequest::Ready(s) => {
859                if let Some((new_state, sas, content)) =
860                    s.start_sas(self.we_started, self.inner.clone().into()).await?
861                {
862                    self.start_sas_helper(new_state, sas, content, other_device_id)
863                } else {
864                    None
865                }
866            }
867            InnerRequest::Transitioned(s) => {
868                if let Some((new_state, sas, content)) =
869                    s.start_sas(self.we_started, self.inner.clone().into()).await?
870                {
871                    self.start_sas_helper(new_state, sas, content, other_device_id)
872                } else {
873                    None
874                }
875            }
876            _ => None,
877        })
878    }
879
880    /// Listen for changes in the verification request.
881    ///
882    /// The changes are presented as a stream of [`VerificationRequestState`]
883    /// values.
884    pub fn changes(&self) -> impl Stream<Item = VerificationRequestState> {
885        self.inner.subscribe().map(|s| (&s).into())
886    }
887
888    /// Get the current state the verification request is in.
889    ///
890    /// To listen to changes to the [`VerificationRequestState`] use the
891    /// [`VerificationRequest::changes`] method.
892    pub fn state(&self) -> VerificationRequestState {
893        (&*self.inner.read()).into()
894    }
895}
896
897#[derive(Clone, Debug)]
898enum InnerRequest {
899    Created(RequestState<Created>),
900    Requested(RequestState<Requested>),
901    Ready(RequestState<Ready>),
902    Transitioned(RequestState<Transitioned>),
903    Passive(RequestState<Passive>),
904    #[allow(dead_code)] // The `RequestState` field within `Done` is not currently used.
905    Done(RequestState<Done>),
906    Cancelled(RequestState<Cancelled>),
907}
908
909impl InnerRequest {
910    fn other_device_id(&self) -> DeviceIdOrAllDevices {
911        match self {
912            InnerRequest::Created(_) => DeviceIdOrAllDevices::AllDevices,
913            InnerRequest::Requested(r) => {
914                DeviceIdOrAllDevices::DeviceId(r.state.other_device_data.device_id().to_owned())
915            }
916            InnerRequest::Ready(r) => {
917                DeviceIdOrAllDevices::DeviceId(r.state.other_device_data.device_id().to_owned())
918            }
919            InnerRequest::Transitioned(r) => DeviceIdOrAllDevices::DeviceId(
920                r.state.ready.other_device_data.device_id().to_owned(),
921            ),
922            InnerRequest::Passive(_) => DeviceIdOrAllDevices::AllDevices,
923            InnerRequest::Done(_) => DeviceIdOrAllDevices::AllDevices,
924            InnerRequest::Cancelled(_) => DeviceIdOrAllDevices::AllDevices,
925        }
926    }
927
928    fn accept(&self, methods: Vec<VerificationMethod>) -> Option<(InnerRequest, OutgoingContent)> {
929        let InnerRequest::Requested(s) = self else { return None };
930        let (state, content) = s.clone().accept(methods);
931
932        Some((InnerRequest::Ready(state), content))
933    }
934
935    fn receive_done(&self, content: &DoneContent<'_>) -> Option<InnerRequest> {
936        let state = InnerRequest::Done(match self {
937            InnerRequest::Transitioned(s) => s.clone().into_done(content),
938            InnerRequest::Passive(s) => s.clone().into_done(content),
939            InnerRequest::Done(_)
940            | InnerRequest::Ready(_)
941            | InnerRequest::Created(_)
942            | InnerRequest::Requested(_)
943            | InnerRequest::Cancelled(_) => return None,
944        });
945
946        Some(state)
947    }
948
949    fn cancel(&self, cancelled_by_us: bool, cancel_code: &CancelCode) -> Option<InnerRequest> {
950        let print_info = || {
951            trace!(
952                cancelled_by_us = cancelled_by_us,
953                code = cancel_code.as_str(),
954                "Verification request going into the cancelled state"
955            );
956        };
957
958        let state = InnerRequest::Cancelled(match self {
959            InnerRequest::Created(s) => {
960                print_info();
961                s.clone().into_canceled(cancelled_by_us, cancel_code)
962            }
963            InnerRequest::Requested(s) => {
964                print_info();
965                s.clone().into_canceled(cancelled_by_us, cancel_code)
966            }
967            InnerRequest::Ready(s) => {
968                print_info();
969                s.clone().into_canceled(cancelled_by_us, cancel_code)
970            }
971            InnerRequest::Transitioned(s) => {
972                print_info();
973                s.clone().into_canceled(cancelled_by_us, cancel_code)
974            }
975            InnerRequest::Passive(_) | InnerRequest::Done(_) | InnerRequest::Cancelled(_) => {
976                return None
977            }
978        });
979
980        Some(state)
981    }
982
983    #[cfg(feature = "qrcode")]
984    async fn generate_qr_code(
985        &self,
986        we_started: bool,
987        request_handle: RequestHandle,
988    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
989        match self {
990            InnerRequest::Created(_)
991            | InnerRequest::Requested(_)
992            | InnerRequest::Passive(_)
993            | InnerRequest::Done(_)
994            | InnerRequest::Cancelled(_) => Ok(None),
995            InnerRequest::Ready(s) => s.generate_qr_code(we_started, request_handle).await,
996            InnerRequest::Transitioned(s) => s.generate_qr_code(we_started, request_handle).await,
997        }
998    }
999}
1000
1001#[derive(Clone, Debug)]
1002struct RequestState<S: Clone> {
1003    verification_cache: VerificationCache,
1004    store: VerificationStore,
1005    flow_id: Arc<FlowId>,
1006
1007    /// The id of the user which is participating in this verification request.
1008    pub other_user_id: OwnedUserId,
1009
1010    /// The verification request state we are in.
1011    state: S,
1012}
1013
1014impl<S: Clone> RequestState<S> {
1015    fn into_done(self, _: &DoneContent<'_>) -> RequestState<Done> {
1016        RequestState::<Done> {
1017            verification_cache: self.verification_cache,
1018            store: self.store,
1019            flow_id: self.flow_id,
1020            other_user_id: self.other_user_id,
1021            state: Done {},
1022        }
1023    }
1024
1025    fn into_canceled(
1026        self,
1027        cancelled_by_us: bool,
1028        cancel_code: &CancelCode,
1029    ) -> RequestState<Cancelled> {
1030        RequestState::<Cancelled> {
1031            verification_cache: self.verification_cache,
1032            store: self.store,
1033            flow_id: self.flow_id,
1034            other_user_id: self.other_user_id,
1035            state: Cancelled::new(cancelled_by_us, cancel_code.clone()),
1036        }
1037    }
1038}
1039
1040impl RequestState<Created> {
1041    fn new(
1042        cache: VerificationCache,
1043        store: VerificationStore,
1044        other_user_id: &UserId,
1045        flow_id: &FlowId,
1046        methods: Option<Vec<VerificationMethod>>,
1047    ) -> Self {
1048        let our_methods = methods.unwrap_or_else(|| SUPPORTED_METHODS.to_vec());
1049
1050        Self {
1051            other_user_id: other_user_id.to_owned(),
1052            state: Created { our_methods },
1053            verification_cache: cache,
1054            store,
1055            flow_id: flow_id.to_owned().into(),
1056        }
1057    }
1058
1059    fn into_ready(
1060        self,
1061        _sender: &UserId,
1062        content: &ReadyContent<'_>,
1063        from_device_data: DeviceData,
1064    ) -> RequestState<Ready> {
1065        // TODO check the flow id, and that the methods match what we suggested.
1066        RequestState {
1067            flow_id: self.flow_id,
1068            verification_cache: self.verification_cache,
1069            store: self.store,
1070            other_user_id: self.other_user_id,
1071            state: Ready {
1072                their_methods: content.methods().to_owned(),
1073                our_methods: self.state.our_methods,
1074                other_device_data: from_device_data,
1075            },
1076        }
1077    }
1078}
1079
1080#[derive(Clone, Debug)]
1081struct Created {
1082    /// The verification methods supported by us.
1083    pub our_methods: Vec<VerificationMethod>,
1084}
1085
1086#[derive(Clone, Debug)]
1087struct Requested {
1088    /// The verification methods supported by the sender.
1089    pub their_methods: Vec<VerificationMethod>,
1090
1091    /// The device data of the device that responded to the verification
1092    /// request.
1093    pub other_device_data: DeviceData,
1094}
1095
1096impl RequestState<Requested> {
1097    fn from_request_event(
1098        cache: VerificationCache,
1099        store: VerificationStore,
1100        sender: &UserId,
1101        flow_id: &FlowId,
1102        content: &RequestContent<'_>,
1103        device_data: DeviceData,
1104    ) -> RequestState<Requested> {
1105        // TODO only create this if we support the methods
1106        RequestState {
1107            store,
1108            verification_cache: cache,
1109            flow_id: flow_id.to_owned().into(),
1110            other_user_id: sender.to_owned(),
1111            state: Requested {
1112                their_methods: content.methods().to_owned(),
1113                other_device_data: device_data,
1114            },
1115        }
1116    }
1117
1118    fn into_passive(self, content: &ReadyContent<'_>) -> RequestState<Passive> {
1119        RequestState {
1120            flow_id: self.flow_id,
1121            verification_cache: self.verification_cache,
1122            store: self.store,
1123            other_user_id: self.other_user_id,
1124            state: Passive { other_device_id: content.from_device().to_owned() },
1125        }
1126    }
1127
1128    fn accept(self, methods: Vec<VerificationMethod>) -> (RequestState<Ready>, OutgoingContent) {
1129        let state = RequestState {
1130            store: self.store,
1131            verification_cache: self.verification_cache,
1132            flow_id: self.flow_id.clone(),
1133            other_user_id: self.other_user_id,
1134            state: Ready {
1135                their_methods: self.state.their_methods,
1136                our_methods: methods.clone(),
1137                other_device_data: self.state.other_device_data,
1138            },
1139        };
1140
1141        let content = match self.flow_id.as_ref() {
1142            FlowId::ToDevice(i) => AnyToDeviceEventContent::KeyVerificationReady(
1143                ToDeviceKeyVerificationReadyEventContent::new(
1144                    state.store.account.device_id.clone(),
1145                    methods,
1146                    i.to_owned(),
1147                ),
1148            )
1149            .into(),
1150            FlowId::InRoom(r, e) => (
1151                r.to_owned(),
1152                AnyMessageLikeEventContent::KeyVerificationReady(
1153                    KeyVerificationReadyEventContent::new(
1154                        state.store.account.device_id.clone(),
1155                        methods,
1156                        Reference::new(e.to_owned()),
1157                    ),
1158                ),
1159            )
1160                .into(),
1161        };
1162
1163        (state, content)
1164    }
1165}
1166
1167#[derive(Clone, Debug)]
1168struct Ready {
1169    /// The verification methods supported by the other side.
1170    pub their_methods: Vec<VerificationMethod>,
1171
1172    /// The verification methods supported by the us.
1173    pub our_methods: Vec<VerificationMethod>,
1174
1175    /// The device data of the device that responded to the verification
1176    /// request.
1177    pub other_device_data: DeviceData,
1178}
1179
1180#[cfg(feature = "qrcode")]
1181async fn scan_qr_code<T: Clone>(
1182    data: QrVerificationData,
1183    request_state: &RequestState<T>,
1184    state: &Ready,
1185    we_started: bool,
1186    request_handle: RequestHandle,
1187) -> Result<(RequestState<Transitioned>, QrVerification), ScanError> {
1188    let verification = QrVerification::from_scan(
1189        request_state.store.to_owned(),
1190        request_state.other_user_id.to_owned(),
1191        state.other_device_data.device_id().to_owned(),
1192        request_state.flow_id.as_ref().to_owned(),
1193        data,
1194        we_started,
1195        Some(request_handle),
1196    )
1197    .await?;
1198
1199    let new_state = RequestState {
1200        verification_cache: request_state.verification_cache.to_owned(),
1201        store: request_state.store.to_owned(),
1202        flow_id: request_state.flow_id.to_owned(),
1203        other_user_id: request_state.other_user_id.to_owned(),
1204        state: Transitioned {
1205            ready: state.to_owned(),
1206            verification: verification.to_owned().into(),
1207            other_device_data: state.other_device_data.to_owned(),
1208        },
1209    };
1210
1211    Ok((new_state, verification))
1212}
1213
1214#[cfg(feature = "qrcode")]
1215async fn generate_qr_code<T: Clone>(
1216    request_state: &RequestState<T>,
1217    state: &Ready,
1218    we_started: bool,
1219    request_handle: RequestHandle,
1220) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1221    use crate::UserIdentityData;
1222
1223    // If we didn't state that we support showing QR codes or if the other
1224    // side doesn't support scanning QR codes bail early.
1225    if !state.our_methods.contains(&VerificationMethod::QrCodeShowV1)
1226        || !state.their_methods.contains(&VerificationMethod::QrCodeScanV1)
1227    {
1228        return Ok(None);
1229    }
1230
1231    let identities = request_state.store.get_identities(state.other_device_data.clone()).await?;
1232
1233    let verification = if let Some(identity) = &identities.identity_being_verified {
1234        match &identity {
1235            UserIdentityData::Own(i) => {
1236                if let Some(master_key) = i.master_key().get_first_key() {
1237                    if identities.can_sign_devices().await {
1238                        if let Some(device_key) = identities.other_device().ed25519_key() {
1239                            Some(QrVerification::new_self(
1240                                request_state.flow_id.as_ref().to_owned(),
1241                                master_key.to_owned(),
1242                                device_key.to_owned(),
1243                                identities,
1244                                we_started,
1245                                Some(request_handle),
1246                            ))
1247                        } else {
1248                            warn!(
1249                                user_id = ?request_state.other_user_id,
1250                                device_id = ?state.other_device_data.device_id(),
1251                                "Can't create a QR code, the other device \
1252                                 doesn't have a valid device key"
1253                            );
1254                            None
1255                        }
1256                    } else {
1257                        Some(QrVerification::new_self_no_master(
1258                            request_state.store.clone(),
1259                            request_state.flow_id.as_ref().to_owned(),
1260                            master_key.to_owned(),
1261                            identities,
1262                            we_started,
1263                            Some(request_handle),
1264                        ))
1265                    }
1266                } else {
1267                    warn!(
1268                        user_id = ?request_state.other_user_id,
1269                        device_id = ?state.other_device_data.device_id(),
1270                        "Can't create a QR code, our cross signing identity \
1271                         doesn't contain a valid master key"
1272                    );
1273                    None
1274                }
1275            }
1276            UserIdentityData::Other(i) => {
1277                if let Some(other_master) = i.master_key().get_first_key() {
1278                    // TODO we can get the master key from the public
1279                    // identity if we don't have the private one and we
1280                    // trust the public one.
1281                    if let Some(own_master) = identities
1282                        .private_identity
1283                        .master_public_key()
1284                        .await
1285                        .and_then(|m| m.get_first_key().map(|m| m.to_owned()))
1286                    {
1287                        Some(QrVerification::new_cross(
1288                            request_state.flow_id.as_ref().to_owned(),
1289                            own_master,
1290                            other_master.to_owned(),
1291                            identities,
1292                            we_started,
1293                            Some(request_handle),
1294                        ))
1295                    } else {
1296                        warn!(
1297                            user_id = ?request_state.other_user_id,
1298                            device_id = ?state.other_device_data.device_id(),
1299                            "Can't create a QR code, we don't trust our own \
1300                             master key"
1301                        );
1302                        None
1303                    }
1304                } else {
1305                    warn!(
1306                        user_id = ?request_state.other_user_id,
1307                        device_id = ?state.other_device_data.device_id(),
1308                        "Can't create a QR code, the user's identity \
1309                         doesn't have a valid master key"
1310                    );
1311                    None
1312                }
1313            }
1314        }
1315    } else {
1316        warn!(
1317            user_id = ?request_state.other_user_id,
1318            device_id = ?state.other_device_data.device_id(),
1319            "Can't create a QR code, the user doesn't have a valid cross \
1320             signing identity."
1321        );
1322
1323        None
1324    };
1325
1326    if let Some(verification) = verification {
1327        let new_state = RequestState {
1328            verification_cache: request_state.verification_cache.to_owned(),
1329            store: request_state.store.to_owned(),
1330            flow_id: request_state.flow_id.to_owned(),
1331            other_user_id: request_state.other_user_id.to_owned(),
1332            state: Transitioned {
1333                ready: state.to_owned(),
1334                verification: verification.to_owned().into(),
1335                other_device_data: state.other_device_data.to_owned(),
1336            },
1337        };
1338
1339        request_state.verification_cache.insert_qr(verification.to_owned());
1340
1341        Ok(Some((new_state, verification)))
1342    } else {
1343        Ok(None)
1344    }
1345}
1346
1347async fn receive_start<T: Clone>(
1348    sender: &UserId,
1349    content: &StartContent<'_>,
1350    we_started: bool,
1351    request_handle: RequestHandle,
1352    request_state: &RequestState<T>,
1353    state: &Ready,
1354) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1355    info!(
1356        ?sender,
1357        device = ?content.from_device(),
1358        method = ?content.method(),
1359        "Received a new verification start event",
1360    );
1361
1362    let other_device_data = state.other_device_data.clone();
1363    let identities = request_state.store.get_identities(other_device_data.clone()).await?;
1364    let own_user_id = &request_state.store.account.user_id;
1365    let own_device_id = &request_state.store.account.device_id;
1366
1367    match content.method() {
1368        StartMethod::SasV1(_) => {
1369            match Sas::from_start_event(
1370                (*request_state.flow_id).to_owned(),
1371                content,
1372                identities,
1373                Some(request_handle),
1374                we_started,
1375            ) {
1376                Ok(new) => {
1377                    let old_verification = request_state
1378                        .verification_cache
1379                        .get(sender, request_state.flow_id.as_str());
1380                    match old_verification {
1381                        Some(Verification::SasV1(_old)) => {
1382                            // If there is already a SAS verification, i.e. we already started one
1383                            // before the other side tried to do the same; ignore it if we did and
1384                            // we're the lexicographically smaller user ID (or device ID if equal).
1385                            use std::cmp::Ordering;
1386                            if !matches!(
1387                                (
1388                                    sender.cmp(own_user_id),
1389                                    other_device_data.device_id().cmp(own_device_id)
1390                                ),
1391                                (Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater)
1392                            ) {
1393                                info!("Started a new SAS verification, replacing an already started one.");
1394                                request_state.verification_cache.replace_sas(new.to_owned());
1395                                Ok(Some(state.to_transitioned(request_state, new.into())))
1396                            } else {
1397                                info!("Ignored incoming SAS verification from lexicographically larger user/device ID.");
1398                                Ok(None)
1399                            }
1400                        }
1401                        #[cfg(feature = "qrcode")]
1402                        Some(Verification::QrV1(old)) => {
1403                            // If there is already a QR verification, our ability to transition to
1404                            // SAS depends on how far we got through the QR flow.
1405                            if let QrVerificationState::Started = old.state() {
1406                                // it is legit to transition from QR display to SAS
1407                                info!("Transitioned from QR display to SAS");
1408                                request_state.verification_cache.replace_sas(new.to_owned());
1409                                Ok(Some(state.to_transitioned(request_state, new.into())))
1410                            } else {
1411                                // otherwise, we've either scanned their QR code, or they have
1412                                // scanned ours -- i.e., an `m.key.verification.start` with method
1413                                // `m.reciprocate.v1` has already been sent/received and, per the
1414                                // spec, it is too late to switch to SAS.
1415                                warn!(qr_state = ?old.state(), "Invalid transition from QR to SAS");
1416                                request_state.verification_cache.insert_sas(new.to_owned());
1417                                Ok(Some(state.to_transitioned(request_state, new.into())))
1418                            }
1419                        }
1420                        None => {
1421                            info!("Started a new SAS verification.");
1422                            request_state.verification_cache.insert_sas(new.to_owned());
1423                            Ok(Some(state.to_transitioned(request_state, new.into())))
1424                        }
1425                    }
1426                }
1427                Err(c) => {
1428                    warn!(
1429                        user_id = ?other_device_data.user_id(),
1430                        device_id = ?other_device_data.device_id(),
1431                        content = ?c,
1432                        "Can't start key verification, canceling.",
1433                    );
1434                    request_state.verification_cache.queue_up_content(
1435                        other_device_data.user_id(),
1436                        other_device_data.device_id(),
1437                        c,
1438                        None,
1439                    );
1440
1441                    Ok(None)
1442                }
1443            }
1444        }
1445        #[cfg(feature = "qrcode")]
1446        StartMethod::ReciprocateV1(_) => {
1447            if let Some(qr_verification) =
1448                request_state.verification_cache.get_qr(sender, content.flow_id())
1449            {
1450                if let Some(request) = qr_verification.receive_reciprocation(content) {
1451                    request_state.verification_cache.add_request(request.into())
1452                }
1453                debug!(
1454                    sender = ?identities.device_being_verified.user_id(),
1455                    device_id = ?identities.device_being_verified.device_id(),
1456                    verification = ?qr_verification,
1457                    "Received a QR code reciprocation"
1458                );
1459
1460                Ok(None)
1461            } else {
1462                warn!("Received a QR code reciprocation for an unknown flow");
1463                Ok(None)
1464            }
1465        }
1466        m => {
1467            warn!(method = ?m, "Received a key verification start event with an unsupported method");
1468            Ok(None)
1469        }
1470    }
1471}
1472
1473async fn start_sas<T: Clone>(
1474    request_state: &RequestState<T>,
1475    state: &Ready,
1476    we_started: bool,
1477    request_handle: RequestHandle,
1478) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1479    if !state.their_methods.contains(&VerificationMethod::SasV1) {
1480        return Ok(None);
1481    }
1482
1483    let identities = request_state.store.get_identities(state.other_device_data.clone()).await?;
1484
1485    let (state, sas, content) = match request_state.flow_id.as_ref() {
1486        FlowId::ToDevice(t) => {
1487            let (sas, content) =
1488                Sas::start(identities, t.to_owned(), we_started, Some(request_handle), None);
1489
1490            let state = Transitioned {
1491                ready: state.to_owned(),
1492                verification: sas.to_owned().into(),
1493                other_device_data: state.other_device_data.to_owned(),
1494            };
1495
1496            (state, sas, content)
1497        }
1498        FlowId::InRoom(r, e) => {
1499            let (sas, content) = Sas::start_in_room(
1500                e.to_owned(),
1501                r.to_owned(),
1502                identities,
1503                we_started,
1504                request_handle,
1505            );
1506            let state = Transitioned {
1507                ready: state.to_owned(),
1508                verification: sas.to_owned().into(),
1509                other_device_data: state.other_device_data.to_owned(),
1510            };
1511            (state, sas, content)
1512        }
1513    };
1514
1515    let state = RequestState {
1516        verification_cache: request_state.verification_cache.to_owned(),
1517        store: request_state.store.to_owned(),
1518        flow_id: request_state.flow_id.to_owned(),
1519        other_user_id: request_state.other_user_id.to_owned(),
1520        state,
1521    };
1522
1523    Ok(Some((state, sas, content)))
1524}
1525
1526impl RequestState<Ready> {
1527    #[cfg(feature = "qrcode")]
1528    async fn generate_qr_code(
1529        &self,
1530        we_started: bool,
1531        request_handle: RequestHandle,
1532    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1533        generate_qr_code(self, &self.state, we_started, request_handle).await
1534    }
1535
1536    async fn receive_start(
1537        &self,
1538        sender: &UserId,
1539        content: &StartContent<'_>,
1540        we_started: bool,
1541        request_handle: RequestHandle,
1542    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1543        receive_start(sender, content, we_started, request_handle, self, &self.state).await
1544    }
1545
1546    async fn start_sas(
1547        &self,
1548        we_started: bool,
1549        request_handle: RequestHandle,
1550    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1551        start_sas(self, &self.state, we_started, request_handle).await
1552    }
1553}
1554
1555impl Ready {
1556    fn to_transitioned<T: Clone>(
1557        &self,
1558        request_state: &RequestState<T>,
1559        verification: Verification,
1560    ) -> RequestState<Transitioned> {
1561        RequestState {
1562            verification_cache: request_state.verification_cache.to_owned(),
1563            store: request_state.store.to_owned(),
1564            flow_id: request_state.flow_id.to_owned(),
1565            other_user_id: request_state.other_user_id.to_owned(),
1566            state: Transitioned {
1567                ready: self.clone(),
1568                verification,
1569                other_device_data: self.other_device_data.clone(),
1570            },
1571        }
1572    }
1573}
1574
1575#[derive(Clone, Debug)]
1576struct Transitioned {
1577    ready: Ready,
1578    verification: Verification,
1579    other_device_data: DeviceData,
1580}
1581
1582impl RequestState<Transitioned> {
1583    #[cfg(feature = "qrcode")]
1584    async fn generate_qr_code(
1585        &self,
1586        we_started: bool,
1587        request_handle: RequestHandle,
1588    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1589        generate_qr_code(self, &self.state.ready, we_started, request_handle).await
1590    }
1591
1592    async fn receive_start(
1593        &self,
1594        sender: &UserId,
1595        content: &StartContent<'_>,
1596        we_started: bool,
1597        request_handle: RequestHandle,
1598    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1599        receive_start(sender, content, we_started, request_handle, self, &self.state.ready).await
1600    }
1601
1602    async fn start_sas(
1603        &self,
1604        we_started: bool,
1605        request_handle: RequestHandle,
1606    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1607        start_sas(self, &self.state.ready, we_started, request_handle).await
1608    }
1609}
1610
1611#[derive(Clone, Debug)]
1612struct Passive {
1613    /// The device ID of the device that responded to the verification request.
1614    #[allow(dead_code)]
1615    pub other_device_id: OwnedDeviceId,
1616}
1617
1618#[derive(Clone, Debug)]
1619struct Done {}
1620
1621#[cfg(test)]
1622mod tests {
1623
1624    use std::time::Duration;
1625
1626    use assert_matches::assert_matches;
1627    use assert_matches2::assert_let;
1628    #[cfg(feature = "qrcode")]
1629    use matrix_sdk_qrcode::QrVerificationData;
1630    use matrix_sdk_test::async_test;
1631    use ruma::{
1632        event_id, events::key::verification::VerificationMethod, room_id,
1633        to_device::DeviceIdOrAllDevices, UserId,
1634    };
1635
1636    use super::VerificationRequest;
1637    use crate::{
1638        types::requests::OutgoingVerificationRequest,
1639        verification::{
1640            cache::VerificationCache,
1641            event_enums::{
1642                CancelContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
1643            },
1644            tests::{alice_id, bob_id, setup_stores},
1645            FlowId, Verification, VerificationStore,
1646        },
1647        DeviceData, VerificationRequestState,
1648    };
1649
1650    #[async_test]
1651    async fn test_request_accepting() {
1652        let event_id = event_id!("$1234localhost").to_owned();
1653        let room_id = room_id!("!test:localhost").to_owned();
1654
1655        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1656
1657        let alice_device_data = DeviceData::from_account(&alice);
1658        let bob_device_data = DeviceData::from_account(&bob);
1659
1660        let content = VerificationRequest::request(
1661            &bob_store.account.user_id,
1662            &bob_store.account.device_id,
1663            alice_id(),
1664            None,
1665        );
1666
1667        let flow_id = FlowId::InRoom(room_id, event_id);
1668
1669        let bob_request = VerificationRequest::new(
1670            VerificationCache::new(),
1671            bob_store,
1672            flow_id.clone(),
1673            alice_id(),
1674            vec![],
1675            None,
1676        );
1677
1678        assert_matches!(bob_request.state(), VerificationRequestState::Created { .. });
1679        assert!(bob_request.time_remaining() <= Duration::from_secs(600)); // 10 minutes
1680        assert!(bob_request.time_remaining() > Duration::from_secs(540)); // 9 minutes
1681
1682        #[allow(clippy::needless_borrow)]
1683        let alice_request = VerificationRequest::from_request(
1684            VerificationCache::new(),
1685            alice_store,
1686            bob_id(),
1687            flow_id,
1688            &(&content).into(),
1689            bob_device_data,
1690        );
1691
1692        assert_matches!(alice_request.state(), VerificationRequestState::Requested { .. });
1693
1694        let content: OutgoingContent = alice_request.accept().unwrap().try_into().unwrap();
1695        let content = ReadyContent::try_from(&content).unwrap();
1696
1697        bob_request.receive_ready(alice_id(), &content, alice_device_data);
1698
1699        assert_matches!(bob_request.state(), VerificationRequestState::Ready { .. });
1700        assert_matches!(alice_request.state(), VerificationRequestState::Ready { .. });
1701        assert!(bob_request.is_ready());
1702        assert!(alice_request.is_ready());
1703    }
1704
1705    #[async_test]
1706    async fn test_request_refusal_to_device() {
1707        // test what happens when we cancel() a request that we have just received over
1708        // to-device messages.
1709        let (_alice, alice_store, bob, bob_store) = setup_stores().await;
1710        let bob_device = DeviceData::from_account(&bob);
1711
1712        // Set up the pair of verification requests
1713        let bob_request = build_test_request(&bob_store, alice_id(), None);
1714        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1715
1716        let outgoing_request = alice_request.cancel().unwrap();
1717
1718        // the outgoing message should target bob's device specifically
1719        {
1720            assert_let!(
1721                OutgoingVerificationRequest::ToDevice(to_device_request) = &outgoing_request
1722            );
1723
1724            assert_eq!(to_device_request.messages.len(), 1);
1725            let device_ids: Vec<&DeviceIdOrAllDevices> =
1726                to_device_request.messages.values().next().unwrap().keys().collect();
1727            assert_eq!(device_ids.len(), 1);
1728
1729            assert_let!(DeviceIdOrAllDevices::DeviceId(device_id) = &device_ids[0]);
1730            assert_eq!(device_id, bob_device.device_id());
1731        }
1732
1733        let content = OutgoingContent::try_from(outgoing_request).unwrap();
1734        let content = CancelContent::try_from(&content).unwrap();
1735
1736        bob_request.receive_cancel(alice_id(), &content);
1737
1738        assert_matches!(bob_request.state(), VerificationRequestState::Cancelled { .. });
1739        assert_matches!(alice_request.state(), VerificationRequestState::Cancelled { .. });
1740    }
1741
1742    #[async_test]
1743    async fn test_requesting_until_sas() {
1744        let event_id = event_id!("$1234localhost");
1745        let room_id = room_id!("!test:localhost");
1746
1747        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1748
1749        let alice_device_data = DeviceData::from_account(&alice);
1750        let bob_device_data = DeviceData::from_account(&bob);
1751
1752        let content = VerificationRequest::request(
1753            &bob_store.account.user_id,
1754            &bob_store.account.device_id,
1755            alice_id(),
1756            None,
1757        );
1758
1759        let flow_id = FlowId::from((room_id, event_id));
1760
1761        let bob_request = VerificationRequest::new(
1762            VerificationCache::new(),
1763            bob_store,
1764            flow_id.clone(),
1765            alice_id(),
1766            vec![],
1767            None,
1768        );
1769
1770        #[allow(clippy::needless_borrow)]
1771        let alice_request = VerificationRequest::from_request(
1772            VerificationCache::new(),
1773            alice_store,
1774            bob_id(),
1775            flow_id,
1776            &(&content).into(),
1777            bob_device_data.clone(),
1778        );
1779
1780        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1781
1782        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1783
1784        let content: OutgoingContent = request.try_into().unwrap();
1785        let content = StartContent::try_from(&content).unwrap();
1786        let flow_id = content.flow_id().to_owned();
1787        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1788        let alice_sas =
1789            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1790
1791        assert_let!(
1792            VerificationRequestState::Transitioned {
1793                verification: Verification::SasV1(_),
1794                other_device_data
1795            } = alice_request.state()
1796        );
1797
1798        assert_eq!(bob_device_data, other_device_data);
1799
1800        assert_let!(
1801            VerificationRequestState::Transitioned {
1802                verification: Verification::SasV1(_),
1803                other_device_data
1804            } = bob_request.state()
1805        );
1806
1807        assert_eq!(alice_device_data, other_device_data);
1808
1809        assert!(!bob_sas.is_cancelled());
1810        assert!(!alice_sas.is_cancelled());
1811    }
1812
1813    #[async_test]
1814    async fn test_requesting_until_sas_to_device() {
1815        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1816
1817        let alice_device_data = DeviceData::from_account(&alice);
1818        let bob_device_data = DeviceData::from_account(&bob);
1819
1820        // Set up the pair of verification requests
1821        let bob_request = build_test_request(&bob_store, alice_id(), None);
1822        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1823        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1824
1825        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1826
1827        let content: OutgoingContent = request.try_into().unwrap();
1828        let content = StartContent::try_from(&content).unwrap();
1829        let flow_id = content.flow_id().to_owned();
1830        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1831        let alice_sas =
1832            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1833
1834        assert_let!(
1835            VerificationRequestState::Transitioned {
1836                verification: Verification::SasV1(_),
1837                other_device_data
1838            } = alice_request.state()
1839        );
1840
1841        assert_eq!(bob_device_data, other_device_data);
1842
1843        assert_let!(
1844            VerificationRequestState::Transitioned {
1845                verification: Verification::SasV1(_),
1846                other_device_data
1847            } = bob_request.state()
1848        );
1849
1850        assert_eq!(alice_device_data, other_device_data);
1851
1852        assert!(!bob_sas.is_cancelled());
1853        assert!(!alice_sas.is_cancelled());
1854        assert!(alice_sas.started_from_request());
1855        assert!(bob_sas.started_from_request());
1856    }
1857
1858    #[async_test]
1859    #[cfg(feature = "qrcode")]
1860    async fn test_can_scan_another_qr_after_creating_mine() {
1861        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1862
1863        let alice_device_data = DeviceData::from_account(&alice);
1864        let bob_device_data = DeviceData::from_account(&bob);
1865
1866        // Set up the pair of verification requests
1867        let bob_request = build_test_request(
1868            &bob_store,
1869            alice_id(),
1870            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1871        );
1872        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1873        do_accept_request(
1874            &alice_request,
1875            alice_device_data.clone(),
1876            &bob_request,
1877            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1878        );
1879
1880        // Each side can start its own QR verification flow by generating QR code
1881        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1882        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1883
1884        assert_let!(
1885            VerificationRequestState::Transitioned {
1886                verification: Verification::QrV1(_),
1887                other_device_data
1888            } = alice_request.state()
1889        );
1890
1891        assert_eq!(bob_device_data, other_device_data);
1892
1893        assert_let!(
1894            VerificationRequestState::Transitioned {
1895                verification: Verification::QrV1(_),
1896                other_device_data
1897            } = bob_request.state()
1898        );
1899
1900        assert_eq!(alice_device_data, other_device_data);
1901
1902        assert!(alice_verification.is_some());
1903        assert!(bob_verification.is_some());
1904
1905        // Now only Alice scans Bob's code
1906        let bob_qr_code = bob_verification.unwrap().to_bytes().unwrap();
1907        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
1908        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
1909
1910        assert_let!(
1911            VerificationRequestState::Transitioned {
1912                verification: Verification::QrV1(alice_verification),
1913                other_device_data
1914            } = alice_request.state()
1915        );
1916
1917        assert_eq!(bob_device_data, other_device_data);
1918
1919        // Finally we assert that the verification has been reciprocated rather than
1920        // cancelled due to a duplicate verification flow
1921        assert!(!alice_verification.is_cancelled());
1922        assert!(alice_verification.reciprocated());
1923    }
1924
1925    #[async_test]
1926    #[cfg(feature = "qrcode")]
1927    async fn test_can_start_sas_after_generating_qr_code() {
1928        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1929
1930        let alice_device_data = DeviceData::from_account(&alice);
1931        let bob_device_data = DeviceData::from_account(&bob);
1932
1933        // Set up the pair of verification requests
1934        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
1935        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1936        do_accept_request(
1937            &alice_request,
1938            alice_device_data.clone(),
1939            &bob_request,
1940            Some(all_methods()),
1941        );
1942
1943        // Each side can start its own QR verification flow by generating QR code
1944        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1945        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1946
1947        assert_let!(
1948            VerificationRequestState::Transitioned {
1949                verification: Verification::QrV1(_),
1950                other_device_data
1951            } = alice_request.state()
1952        );
1953
1954        assert_eq!(bob_device_data, other_device_data);
1955
1956        assert!(alice_verification.is_some());
1957        assert!(bob_verification.is_some());
1958
1959        // Alice can now start SAS verification flow instead of QR without cancelling
1960        // the request
1961        let (sas, request) = alice_request.start_sas().await.unwrap().unwrap();
1962        assert_let!(
1963            VerificationRequestState::Transitioned {
1964                verification: Verification::SasV1(_),
1965                other_device_data
1966            } = alice_request.state()
1967        );
1968
1969        assert_eq!(bob_device_data, other_device_data);
1970        assert!(!sas.is_cancelled());
1971
1972        // Bob receives the SAS start
1973        let content: OutgoingContent = request.try_into().unwrap();
1974        let content = StartContent::try_from(&content).unwrap();
1975        bob_request.receive_start(alice_id(), &content).await.unwrap();
1976
1977        // Bob should now have transitioned to SAS...
1978        assert_let!(
1979            VerificationRequestState::Transitioned {
1980                verification: Verification::SasV1(bob_sas),
1981                other_device_data
1982            } = bob_request.state()
1983        );
1984
1985        assert_eq!(alice_device_data, other_device_data);
1986
1987        // ... and, more to the point, it should not be cancelled.
1988        assert!(!bob_sas.is_cancelled());
1989    }
1990
1991    #[async_test]
1992    #[cfg(feature = "qrcode")]
1993    async fn test_start_sas_after_scan_cancels_request() {
1994        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1995
1996        let alice_device_data = DeviceData::from_account(&alice);
1997        let bob_device_data = DeviceData::from_account(&bob);
1998
1999        // Set up the pair of verification requests
2000        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
2001        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
2002        do_accept_request(
2003            &alice_request,
2004            alice_device_data.clone(),
2005            &bob_request,
2006            Some(all_methods()),
2007        );
2008
2009        // Bob generates a QR code
2010        let bob_verification = bob_request.generate_qr_code().await.unwrap().unwrap();
2011        assert_let!(
2012            VerificationRequestState::Transitioned {
2013                verification: Verification::QrV1(_),
2014                other_device_data
2015            } = bob_request.state()
2016        );
2017
2018        assert_eq!(alice_device_data, other_device_data);
2019
2020        // Now Alice scans Bob's code
2021        let bob_qr_code = bob_verification.to_bytes().unwrap();
2022        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
2023        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
2024
2025        assert_let!(
2026            VerificationRequestState::Transitioned {
2027                verification: Verification::QrV1(alice_qr),
2028                other_device_data
2029            } = alice_request.state()
2030        );
2031
2032        assert_eq!(bob_device_data, other_device_data);
2033        assert!(alice_qr.reciprocated());
2034
2035        // But Bob wants to do an SAS verification!
2036        let (_, request) = bob_request.start_sas().await.unwrap().unwrap();
2037        assert_let!(
2038            VerificationRequestState::Transitioned {
2039                verification: Verification::SasV1(_),
2040                other_device_data
2041            } = bob_request.state()
2042        );
2043
2044        assert_eq!(alice_device_data, other_device_data);
2045
2046        // Alice receives the SAS start
2047        let content: OutgoingContent = request.try_into().unwrap();
2048        let content = StartContent::try_from(&content).unwrap();
2049        alice_request.receive_start(bob_id(), &content).await.unwrap();
2050
2051        // ... which should mean that her Qr is cancelled
2052        assert!(alice_qr.is_cancelled());
2053
2054        // and she should now have a *cancelled* SAS verification
2055        assert_let!(
2056            VerificationRequestState::Transitioned {
2057                verification: Verification::SasV1(alice_sas),
2058                other_device_data
2059            } = alice_request.state()
2060        );
2061
2062        assert_eq!(bob_device_data, other_device_data);
2063        assert!(alice_sas.is_cancelled());
2064    }
2065
2066    /// Build an outgoing Verification request
2067    ///
2068    /// # Arguments
2069    ///
2070    /// * `verification_store` - The `VerificationStore` for the user making the
2071    ///   request.
2072    /// * `other_user_id` - The ID of the user we want to verify
2073    /// * `methods` - A list of `VerificationMethods` to say we support. If
2074    ///   `None`, will use the default list.
2075    fn build_test_request(
2076        verification_store: &VerificationStore,
2077        other_user_id: &UserId,
2078        methods: Option<Vec<VerificationMethod>>,
2079    ) -> VerificationRequest {
2080        VerificationRequest::new(
2081            VerificationCache::new(),
2082            verification_store.clone(),
2083            FlowId::ToDevice("TEST_FLOW_ID".into()),
2084            other_user_id,
2085            vec![],
2086            methods,
2087        )
2088    }
2089
2090    /// Given an outgoing `VerificationRequest`, create an incoming
2091    /// `VerificationRequest` for the other side.
2092    ///
2093    /// Tells the outgoing request to generate an `m.key.verification.request`
2094    /// to-device message, and uses it to build a new request for the incoming
2095    /// side.
2096    async fn build_incoming_verification_request(
2097        verification_store: &VerificationStore,
2098        outgoing_request: &VerificationRequest,
2099    ) -> VerificationRequest {
2100        let request = outgoing_request.request_to_device();
2101        let content: OutgoingContent = request.try_into().unwrap();
2102        let content = RequestContent::try_from(&content).unwrap();
2103
2104        let device_data = verification_store
2105            .get_device(outgoing_request.own_user_id(), content.from_device())
2106            .await
2107            .unwrap()
2108            .expect("Missing device data");
2109
2110        VerificationRequest::from_request(
2111            VerificationCache::new(),
2112            verification_store.clone(),
2113            outgoing_request.own_user_id(),
2114            outgoing_request.flow_id().clone(),
2115            &content,
2116            device_data,
2117        )
2118    }
2119
2120    /// Have a `VerificationRequest` generate an `m.key.verification.ready` and
2121    /// feed it into another `VerificationRequest`.
2122    ///
2123    /// # Arguments
2124    ///
2125    /// * `accepting_request` - The request which should send the acceptance.
2126    /// * `initiating_request` - The request which initiated the flow -- i.e.,
2127    ///   the one that should *receive* the acceptance.
2128    /// * `methods` - The list of methods to say we support. If `None`, the
2129    ///   default list of methods will be used.
2130    fn do_accept_request(
2131        accepting_request: &VerificationRequest,
2132        accepting_device_data: DeviceData,
2133        initiating_request: &VerificationRequest,
2134        methods: Option<Vec<VerificationMethod>>,
2135    ) {
2136        let request = match methods {
2137            Some(methods) => accepting_request.accept_with_methods(methods),
2138            None => accepting_request.accept(),
2139        };
2140        let content: OutgoingContent = request.unwrap().try_into().unwrap();
2141        let content = ReadyContent::try_from(&content).unwrap();
2142        initiating_request.receive_ready(
2143            accepting_request.own_user_id(),
2144            &content,
2145            accepting_device_data,
2146        );
2147
2148        assert!(initiating_request.is_ready());
2149        assert!(accepting_request.is_ready());
2150    }
2151
2152    /// Get a list of all the verification methods, including those used for QR
2153    /// codes.
2154    #[cfg(feature = "qrcode")]
2155    fn all_methods() -> Vec<VerificationMethod> {
2156        vec![
2157            VerificationMethod::SasV1,
2158            VerificationMethod::QrCodeScanV1,
2159            VerificationMethod::QrCodeShowV1,
2160            VerificationMethod::ReciprocateV1,
2161        ]
2162    }
2163}