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    DeviceId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, RoomId, TransactionId,
25    UserId,
26    events::{
27        AnyMessageLikeEventContent, AnyToDeviceEventContent,
28        key::verification::{
29            VerificationMethod,
30            cancel::CancelCode,
31            ready::{KeyVerificationReadyEventContent, ToDeviceKeyVerificationReadyEventContent},
32            request::ToDeviceKeyVerificationRequestEventContent,
33            start::StartMethod,
34        },
35        relation::Reference,
36        room::message::KeyVerificationRequestEventContent,
37    },
38    time::Instant,
39    to_device::DeviceIdOrAllDevices,
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    CancelInfo, Cancelled, FlowId, Verification, VerificationStore,
49    cache::VerificationCache,
50    event_enums::{
51        CancelContent, DoneContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
52    },
53};
54use crate::{
55    CryptoStoreError, DeviceData, Sas,
56    olm::StaticAccountData,
57    types::requests::{OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest},
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            && 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    fn start_sas_helper(
805        &self,
806        new_state: RequestState<Transitioned>,
807        sas: Sas,
808        content: OutgoingContent,
809        other_device_id: DeviceIdOrAllDevices,
810    ) -> Option<(Sas, OutgoingVerificationRequest)> {
811        // We may have previously started QR verification and generated a QR code. If we
812        // now switch to SAS flow, the previous verification has to be replaced
813        cfg_if::cfg_if! {
814            if #[cfg(feature = "qrcode")] {
815                if self.verification_cache.get_qr(sas.other_user_id(), sas.flow_id().as_str()).is_some() {
816                    debug!(
817                        user_id = ?self.other_user(),
818                        flow_id = self.flow_id().as_str(),
819                        "We have an ongoing QR verification, replacing with SAS"
820                    );
821                    self.verification_cache.replace(sas.clone().into())
822                } else {
823                    self.verification_cache.insert_sas(sas.clone());
824                }
825            } else {
826                self.verification_cache.insert_sas(sas.clone());
827            }
828        }
829
830        let request = match content {
831            OutgoingContent::ToDevice(content) => ToDeviceRequest::with_id(
832                self.other_user(),
833                other_device_id,
834                &content,
835                TransactionId::new(),
836            )
837            .into(),
838            OutgoingContent::Room(room_id, content) => {
839                RoomMessageRequest { room_id, txn_id: TransactionId::new(), content }.into()
840            }
841        };
842
843        let mut guard = self.inner.write();
844        ObservableWriteGuard::set(&mut guard, InnerRequest::Transitioned(new_state));
845
846        Some((sas, request))
847    }
848
849    /// Transition from this verification request into a SAS verification flow.
850    pub async fn start_sas(
851        &self,
852    ) -> Result<Option<(Sas, OutgoingVerificationRequest)>, CryptoStoreError> {
853        let inner = self.inner.get();
854        let other_device_id = inner.other_device_id();
855
856        Ok(match &inner {
857            InnerRequest::Ready(s) => {
858                if let Some((new_state, sas, content)) =
859                    s.start_sas(self.we_started, self.inner.clone().into()).await?
860                {
861                    self.start_sas_helper(new_state, sas, content, other_device_id)
862                } else {
863                    None
864                }
865            }
866            InnerRequest::Transitioned(s) => {
867                if let Some((new_state, sas, content)) =
868                    s.start_sas(self.we_started, self.inner.clone().into()).await?
869                {
870                    self.start_sas_helper(new_state, sas, content, other_device_id)
871                } else {
872                    None
873                }
874            }
875            _ => None,
876        })
877    }
878
879    /// Listen for changes in the verification request.
880    ///
881    /// The changes are presented as a stream of [`VerificationRequestState`]
882    /// values.
883    pub fn changes(&self) -> impl Stream<Item = VerificationRequestState> + use<> {
884        self.inner.subscribe().map(|s| (&s).into())
885    }
886
887    /// Get the current state the verification request is in.
888    ///
889    /// To listen to changes to the [`VerificationRequestState`] use the
890    /// [`VerificationRequest::changes`] method.
891    pub fn state(&self) -> VerificationRequestState {
892        (&*self.inner.read()).into()
893    }
894}
895
896#[derive(Clone, Debug)]
897enum InnerRequest {
898    Created(RequestState<Created>),
899    Requested(RequestState<Requested>),
900    Ready(RequestState<Ready>),
901    Transitioned(RequestState<Transitioned>),
902    Passive(RequestState<Passive>),
903    #[allow(dead_code)] // The `RequestState` field within `Done` is not currently used.
904    Done(RequestState<Done>),
905    Cancelled(RequestState<Cancelled>),
906}
907
908impl InnerRequest {
909    fn other_device_id(&self) -> DeviceIdOrAllDevices {
910        match self {
911            InnerRequest::Created(_) => DeviceIdOrAllDevices::AllDevices,
912            InnerRequest::Requested(r) => {
913                DeviceIdOrAllDevices::DeviceId(r.state.other_device_data.device_id().to_owned())
914            }
915            InnerRequest::Ready(r) => {
916                DeviceIdOrAllDevices::DeviceId(r.state.other_device_data.device_id().to_owned())
917            }
918            InnerRequest::Transitioned(r) => DeviceIdOrAllDevices::DeviceId(
919                r.state.ready.other_device_data.device_id().to_owned(),
920            ),
921            InnerRequest::Passive(_) => DeviceIdOrAllDevices::AllDevices,
922            InnerRequest::Done(_) => DeviceIdOrAllDevices::AllDevices,
923            InnerRequest::Cancelled(_) => DeviceIdOrAllDevices::AllDevices,
924        }
925    }
926
927    fn accept(&self, methods: Vec<VerificationMethod>) -> Option<(InnerRequest, OutgoingContent)> {
928        let InnerRequest::Requested(s) = self else { return None };
929        let (state, content) = s.clone().accept(methods);
930
931        Some((InnerRequest::Ready(state), content))
932    }
933
934    fn receive_done(&self, content: &DoneContent<'_>) -> Option<InnerRequest> {
935        let state = InnerRequest::Done(match self {
936            InnerRequest::Transitioned(s) => s.clone().into_done(content),
937            InnerRequest::Passive(s) => s.clone().into_done(content),
938            InnerRequest::Done(_)
939            | InnerRequest::Ready(_)
940            | InnerRequest::Created(_)
941            | InnerRequest::Requested(_)
942            | InnerRequest::Cancelled(_) => return None,
943        });
944
945        Some(state)
946    }
947
948    fn cancel(&self, cancelled_by_us: bool, cancel_code: &CancelCode) -> Option<InnerRequest> {
949        let print_info = || {
950            trace!(
951                cancelled_by_us,
952                code = cancel_code.as_str(),
953                "Verification request going into the cancelled state"
954            );
955        };
956
957        let state = InnerRequest::Cancelled(match self {
958            InnerRequest::Created(s) => {
959                print_info();
960                s.clone().into_canceled(cancelled_by_us, cancel_code)
961            }
962            InnerRequest::Requested(s) => {
963                print_info();
964                s.clone().into_canceled(cancelled_by_us, cancel_code)
965            }
966            InnerRequest::Ready(s) => {
967                print_info();
968                s.clone().into_canceled(cancelled_by_us, cancel_code)
969            }
970            InnerRequest::Transitioned(s) => {
971                print_info();
972                s.clone().into_canceled(cancelled_by_us, cancel_code)
973            }
974            InnerRequest::Passive(_) | InnerRequest::Done(_) | InnerRequest::Cancelled(_) => {
975                return None;
976            }
977        });
978
979        Some(state)
980    }
981
982    #[cfg(feature = "qrcode")]
983    async fn generate_qr_code(
984        &self,
985        we_started: bool,
986        request_handle: RequestHandle,
987    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
988        match self {
989            InnerRequest::Created(_)
990            | InnerRequest::Requested(_)
991            | InnerRequest::Passive(_)
992            | InnerRequest::Done(_)
993            | InnerRequest::Cancelled(_) => Ok(None),
994            InnerRequest::Ready(s) => s.generate_qr_code(we_started, request_handle).await,
995            InnerRequest::Transitioned(s) => s.generate_qr_code(we_started, request_handle).await,
996        }
997    }
998}
999
1000#[derive(Clone, Debug)]
1001struct RequestState<S: Clone> {
1002    verification_cache: VerificationCache,
1003    store: VerificationStore,
1004    flow_id: Arc<FlowId>,
1005
1006    /// The id of the user which is participating in this verification request.
1007    pub other_user_id: OwnedUserId,
1008
1009    /// The verification request state we are in.
1010    state: S,
1011}
1012
1013impl<S: Clone> RequestState<S> {
1014    fn into_done(self, _: &DoneContent<'_>) -> RequestState<Done> {
1015        RequestState::<Done> {
1016            verification_cache: self.verification_cache,
1017            store: self.store,
1018            flow_id: self.flow_id,
1019            other_user_id: self.other_user_id,
1020            state: Done {},
1021        }
1022    }
1023
1024    fn into_canceled(
1025        self,
1026        cancelled_by_us: bool,
1027        cancel_code: &CancelCode,
1028    ) -> RequestState<Cancelled> {
1029        RequestState::<Cancelled> {
1030            verification_cache: self.verification_cache,
1031            store: self.store,
1032            flow_id: self.flow_id,
1033            other_user_id: self.other_user_id,
1034            state: Cancelled::new(cancelled_by_us, cancel_code.clone()),
1035        }
1036    }
1037}
1038
1039impl RequestState<Created> {
1040    fn new(
1041        cache: VerificationCache,
1042        store: VerificationStore,
1043        other_user_id: &UserId,
1044        flow_id: &FlowId,
1045        methods: Option<Vec<VerificationMethod>>,
1046    ) -> Self {
1047        let our_methods = methods.unwrap_or_else(|| SUPPORTED_METHODS.to_vec());
1048
1049        Self {
1050            other_user_id: other_user_id.to_owned(),
1051            state: Created { our_methods },
1052            verification_cache: cache,
1053            store,
1054            flow_id: flow_id.to_owned().into(),
1055        }
1056    }
1057
1058    fn into_ready(
1059        self,
1060        _sender: &UserId,
1061        content: &ReadyContent<'_>,
1062        from_device_data: DeviceData,
1063    ) -> RequestState<Ready> {
1064        // TODO check the flow id, and that the methods match what we suggested.
1065        RequestState {
1066            flow_id: self.flow_id,
1067            verification_cache: self.verification_cache,
1068            store: self.store,
1069            other_user_id: self.other_user_id,
1070            state: Ready {
1071                their_methods: content.methods().to_owned(),
1072                our_methods: self.state.our_methods,
1073                other_device_data: from_device_data,
1074            },
1075        }
1076    }
1077}
1078
1079#[derive(Clone, Debug)]
1080struct Created {
1081    /// The verification methods supported by us.
1082    pub our_methods: Vec<VerificationMethod>,
1083}
1084
1085#[derive(Clone, Debug)]
1086struct Requested {
1087    /// The verification methods supported by the sender.
1088    pub their_methods: Vec<VerificationMethod>,
1089
1090    /// The device data of the device that responded to the verification
1091    /// request.
1092    pub other_device_data: DeviceData,
1093}
1094
1095impl RequestState<Requested> {
1096    fn from_request_event(
1097        cache: VerificationCache,
1098        store: VerificationStore,
1099        sender: &UserId,
1100        flow_id: &FlowId,
1101        content: &RequestContent<'_>,
1102        device_data: DeviceData,
1103    ) -> RequestState<Requested> {
1104        // TODO only create this if we support the methods
1105        RequestState {
1106            store,
1107            verification_cache: cache,
1108            flow_id: flow_id.to_owned().into(),
1109            other_user_id: sender.to_owned(),
1110            state: Requested {
1111                their_methods: content.methods().to_owned(),
1112                other_device_data: device_data,
1113            },
1114        }
1115    }
1116
1117    fn into_passive(self, content: &ReadyContent<'_>) -> RequestState<Passive> {
1118        RequestState {
1119            flow_id: self.flow_id,
1120            verification_cache: self.verification_cache,
1121            store: self.store,
1122            other_user_id: self.other_user_id,
1123            state: Passive { other_device_id: content.from_device().to_owned() },
1124        }
1125    }
1126
1127    fn accept(self, methods: Vec<VerificationMethod>) -> (RequestState<Ready>, OutgoingContent) {
1128        let state = RequestState {
1129            store: self.store,
1130            verification_cache: self.verification_cache,
1131            flow_id: self.flow_id.clone(),
1132            other_user_id: self.other_user_id,
1133            state: Ready {
1134                their_methods: self.state.their_methods,
1135                our_methods: methods.clone(),
1136                other_device_data: self.state.other_device_data,
1137            },
1138        };
1139
1140        let content = match self.flow_id.as_ref() {
1141            FlowId::ToDevice(i) => AnyToDeviceEventContent::KeyVerificationReady(
1142                ToDeviceKeyVerificationReadyEventContent::new(
1143                    state.store.account.device_id.clone(),
1144                    methods,
1145                    i.to_owned(),
1146                ),
1147            )
1148            .into(),
1149            FlowId::InRoom(r, e) => (
1150                r.to_owned(),
1151                AnyMessageLikeEventContent::KeyVerificationReady(
1152                    KeyVerificationReadyEventContent::new(
1153                        state.store.account.device_id.clone(),
1154                        methods,
1155                        Reference::new(e.to_owned()),
1156                    ),
1157                ),
1158            )
1159                .into(),
1160        };
1161
1162        (state, content)
1163    }
1164}
1165
1166#[derive(Clone, Debug)]
1167struct Ready {
1168    /// The verification methods supported by the other side.
1169    pub their_methods: Vec<VerificationMethod>,
1170
1171    /// The verification methods supported by the us.
1172    pub our_methods: Vec<VerificationMethod>,
1173
1174    /// The device data of the device that responded to the verification
1175    /// request.
1176    pub other_device_data: DeviceData,
1177}
1178
1179#[cfg(feature = "qrcode")]
1180async fn scan_qr_code<T: Clone>(
1181    data: QrVerificationData,
1182    request_state: &RequestState<T>,
1183    state: &Ready,
1184    we_started: bool,
1185    request_handle: RequestHandle,
1186) -> Result<(RequestState<Transitioned>, QrVerification), ScanError> {
1187    let verification = QrVerification::from_scan(
1188        request_state.store.to_owned(),
1189        request_state.other_user_id.to_owned(),
1190        state.other_device_data.device_id().to_owned(),
1191        request_state.flow_id.as_ref().to_owned(),
1192        data,
1193        we_started,
1194        Some(request_handle),
1195    )
1196    .await?;
1197
1198    let new_state = RequestState {
1199        verification_cache: request_state.verification_cache.to_owned(),
1200        store: request_state.store.to_owned(),
1201        flow_id: request_state.flow_id.to_owned(),
1202        other_user_id: request_state.other_user_id.to_owned(),
1203        state: Transitioned {
1204            ready: state.to_owned(),
1205            verification: verification.to_owned().into(),
1206            other_device_data: state.other_device_data.to_owned(),
1207        },
1208    };
1209
1210    Ok((new_state, verification))
1211}
1212
1213#[cfg(feature = "qrcode")]
1214async fn generate_qr_code<T: Clone>(
1215    request_state: &RequestState<T>,
1216    state: &Ready,
1217    we_started: bool,
1218    request_handle: RequestHandle,
1219) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1220    use crate::UserIdentityData;
1221
1222    // If we didn't state that we support showing QR codes or if the other
1223    // side doesn't support scanning QR codes bail early.
1224    if !state.our_methods.contains(&VerificationMethod::QrCodeShowV1)
1225        || !state.their_methods.contains(&VerificationMethod::QrCodeScanV1)
1226    {
1227        return Ok(None);
1228    }
1229
1230    let identities = request_state.store.get_identities(state.other_device_data.clone()).await?;
1231
1232    let verification = if let Some(identity) = &identities.identity_being_verified {
1233        match &identity {
1234            UserIdentityData::Own(i) => {
1235                if let Some(master_key) = i.master_key().get_first_key() {
1236                    if identities.can_sign_devices().await {
1237                        if let Some(device_key) = identities.other_device().ed25519_key() {
1238                            Some(QrVerification::new_self(
1239                                request_state.flow_id.as_ref().to_owned(),
1240                                master_key.to_owned(),
1241                                device_key.to_owned(),
1242                                identities,
1243                                we_started,
1244                                Some(request_handle),
1245                            ))
1246                        } else {
1247                            warn!(
1248                                user_id = ?request_state.other_user_id,
1249                                device_id = ?state.other_device_data.device_id(),
1250                                "Can't create a QR code, the other device \
1251                                 doesn't have a valid device key"
1252                            );
1253                            None
1254                        }
1255                    } else {
1256                        Some(QrVerification::new_self_no_master(
1257                            request_state.store.clone(),
1258                            request_state.flow_id.as_ref().to_owned(),
1259                            master_key.to_owned(),
1260                            identities,
1261                            we_started,
1262                            Some(request_handle),
1263                        ))
1264                    }
1265                } else {
1266                    warn!(
1267                        user_id = ?request_state.other_user_id,
1268                        device_id = ?state.other_device_data.device_id(),
1269                        "Can't create a QR code, our cross signing identity \
1270                         doesn't contain a valid master key"
1271                    );
1272                    None
1273                }
1274            }
1275            UserIdentityData::Other(i) => {
1276                if let Some(other_master) = i.master_key().get_first_key() {
1277                    // TODO we can get the master key from the public
1278                    // identity if we don't have the private one and we
1279                    // trust the public one.
1280                    if let Some(own_master) = identities
1281                        .private_identity
1282                        .master_public_key()
1283                        .await
1284                        .and_then(|m| m.get_first_key().map(|m| m.to_owned()))
1285                    {
1286                        Some(QrVerification::new_cross(
1287                            request_state.flow_id.as_ref().to_owned(),
1288                            own_master,
1289                            other_master.to_owned(),
1290                            identities,
1291                            we_started,
1292                            Some(request_handle),
1293                        ))
1294                    } else {
1295                        warn!(
1296                            user_id = ?request_state.other_user_id,
1297                            device_id = ?state.other_device_data.device_id(),
1298                            "Can't create a QR code, we don't trust our own \
1299                             master key"
1300                        );
1301                        None
1302                    }
1303                } else {
1304                    warn!(
1305                        user_id = ?request_state.other_user_id,
1306                        device_id = ?state.other_device_data.device_id(),
1307                        "Can't create a QR code, the user's identity \
1308                         doesn't have a valid master key"
1309                    );
1310                    None
1311                }
1312            }
1313        }
1314    } else {
1315        warn!(
1316            user_id = ?request_state.other_user_id,
1317            device_id = ?state.other_device_data.device_id(),
1318            "Can't create a QR code, the user doesn't have a valid cross \
1319             signing identity."
1320        );
1321
1322        None
1323    };
1324
1325    if let Some(verification) = verification {
1326        let new_state = RequestState {
1327            verification_cache: request_state.verification_cache.to_owned(),
1328            store: request_state.store.to_owned(),
1329            flow_id: request_state.flow_id.to_owned(),
1330            other_user_id: request_state.other_user_id.to_owned(),
1331            state: Transitioned {
1332                ready: state.to_owned(),
1333                verification: verification.to_owned().into(),
1334                other_device_data: state.other_device_data.to_owned(),
1335            },
1336        };
1337
1338        request_state.verification_cache.insert_qr(verification.to_owned());
1339
1340        Ok(Some((new_state, verification)))
1341    } else {
1342        Ok(None)
1343    }
1344}
1345
1346async fn receive_start<T: Clone>(
1347    sender: &UserId,
1348    content: &StartContent<'_>,
1349    we_started: bool,
1350    request_handle: RequestHandle,
1351    request_state: &RequestState<T>,
1352    state: &Ready,
1353) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1354    info!(
1355        ?sender,
1356        device = ?content.from_device(),
1357        method = ?content.method(),
1358        "Received a new verification start event",
1359    );
1360
1361    let other_device_data = state.other_device_data.clone();
1362    let identities = request_state.store.get_identities(other_device_data.clone()).await?;
1363    let own_user_id = &request_state.store.account.user_id;
1364    let own_device_id = &request_state.store.account.device_id;
1365
1366    match content.method() {
1367        StartMethod::SasV1(_) => {
1368            match Sas::from_start_event(
1369                (*request_state.flow_id).to_owned(),
1370                content,
1371                identities,
1372                Some(request_handle),
1373                we_started,
1374            ) {
1375                Ok(new) => {
1376                    let old_verification = request_state
1377                        .verification_cache
1378                        .get(sender, request_state.flow_id.as_str());
1379                    match old_verification {
1380                        Some(Verification::SasV1(_old)) => {
1381                            // If there is already a SAS verification, i.e. we already started one
1382                            // before the other side tried to do the same; ignore it if we did and
1383                            // we're the lexicographically smaller user ID (or device ID if equal).
1384                            use std::cmp::Ordering;
1385                            if !matches!(
1386                                (
1387                                    sender.cmp(own_user_id),
1388                                    other_device_data.device_id().cmp(own_device_id)
1389                                ),
1390                                (Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater)
1391                            ) {
1392                                info!(
1393                                    "Started a new SAS verification, replacing an already started one."
1394                                );
1395                                request_state.verification_cache.replace_sas(new.to_owned());
1396                                Ok(Some(state.to_transitioned(request_state, new.into())))
1397                            } else {
1398                                info!(
1399                                    "Ignored incoming SAS verification from lexicographically larger user/device ID."
1400                                );
1401                                Ok(None)
1402                            }
1403                        }
1404                        #[cfg(feature = "qrcode")]
1405                        Some(Verification::QrV1(old)) => {
1406                            // If there is already a QR verification, our ability to transition to
1407                            // SAS depends on how far we got through the QR flow.
1408                            if let QrVerificationState::Started = old.state() {
1409                                // it is legit to transition from QR display to SAS
1410                                info!("Transitioned from QR display to SAS");
1411                                request_state.verification_cache.replace_sas(new.to_owned());
1412                                Ok(Some(state.to_transitioned(request_state, new.into())))
1413                            } else {
1414                                // otherwise, we've either scanned their QR code, or they have
1415                                // scanned ours -- i.e., an `m.key.verification.start` with method
1416                                // `m.reciprocate.v1` has already been sent/received and, per the
1417                                // spec, it is too late to switch to SAS.
1418                                warn!(qr_state = ?old.state(), "Invalid transition from QR to SAS");
1419                                request_state.verification_cache.insert_sas(new.to_owned());
1420                                Ok(Some(state.to_transitioned(request_state, new.into())))
1421                            }
1422                        }
1423                        None => {
1424                            info!("Started a new SAS verification.");
1425                            request_state.verification_cache.insert_sas(new.to_owned());
1426                            Ok(Some(state.to_transitioned(request_state, new.into())))
1427                        }
1428                    }
1429                }
1430                Err(c) => {
1431                    warn!(
1432                        user_id = ?other_device_data.user_id(),
1433                        device_id = ?other_device_data.device_id(),
1434                        content = ?c,
1435                        "Can't start key verification, canceling.",
1436                    );
1437                    request_state.verification_cache.queue_up_content(
1438                        other_device_data.user_id(),
1439                        other_device_data.device_id(),
1440                        c,
1441                        None,
1442                    );
1443
1444                    Ok(None)
1445                }
1446            }
1447        }
1448        #[cfg(feature = "qrcode")]
1449        StartMethod::ReciprocateV1(_) => {
1450            if let Some(qr_verification) =
1451                request_state.verification_cache.get_qr(sender, content.flow_id())
1452            {
1453                if let Some(request) = qr_verification.receive_reciprocation(content) {
1454                    request_state.verification_cache.add_request(request.into())
1455                }
1456                debug!(
1457                    sender = ?identities.device_being_verified.user_id(),
1458                    device_id = ?identities.device_being_verified.device_id(),
1459                    verification = ?qr_verification,
1460                    "Received a QR code reciprocation"
1461                );
1462
1463                Ok(None)
1464            } else {
1465                warn!("Received a QR code reciprocation for an unknown flow");
1466                Ok(None)
1467            }
1468        }
1469        m => {
1470            warn!(method = ?m, "Received a key verification start event with an unsupported method");
1471            Ok(None)
1472        }
1473    }
1474}
1475
1476async fn start_sas<T: Clone>(
1477    request_state: &RequestState<T>,
1478    state: &Ready,
1479    we_started: bool,
1480    request_handle: RequestHandle,
1481) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1482    if !state.their_methods.contains(&VerificationMethod::SasV1) {
1483        return Ok(None);
1484    }
1485
1486    let identities = request_state.store.get_identities(state.other_device_data.clone()).await?;
1487
1488    let (state, sas, content) = match request_state.flow_id.as_ref() {
1489        FlowId::ToDevice(t) => {
1490            let (sas, content) =
1491                Sas::start(identities, t.to_owned(), we_started, Some(request_handle), None);
1492
1493            let state = Transitioned {
1494                ready: state.to_owned(),
1495                verification: sas.to_owned().into(),
1496                other_device_data: state.other_device_data.to_owned(),
1497            };
1498
1499            (state, sas, content)
1500        }
1501        FlowId::InRoom(r, e) => {
1502            let (sas, content) = Sas::start_in_room(
1503                e.to_owned(),
1504                r.to_owned(),
1505                identities,
1506                we_started,
1507                request_handle,
1508            );
1509            let state = Transitioned {
1510                ready: state.to_owned(),
1511                verification: sas.to_owned().into(),
1512                other_device_data: state.other_device_data.to_owned(),
1513            };
1514            (state, sas, content)
1515        }
1516    };
1517
1518    let state = RequestState {
1519        verification_cache: request_state.verification_cache.to_owned(),
1520        store: request_state.store.to_owned(),
1521        flow_id: request_state.flow_id.to_owned(),
1522        other_user_id: request_state.other_user_id.to_owned(),
1523        state,
1524    };
1525
1526    Ok(Some((state, sas, content)))
1527}
1528
1529impl RequestState<Ready> {
1530    #[cfg(feature = "qrcode")]
1531    async fn generate_qr_code(
1532        &self,
1533        we_started: bool,
1534        request_handle: RequestHandle,
1535    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1536        generate_qr_code(self, &self.state, we_started, request_handle).await
1537    }
1538
1539    async fn receive_start(
1540        &self,
1541        sender: &UserId,
1542        content: &StartContent<'_>,
1543        we_started: bool,
1544        request_handle: RequestHandle,
1545    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1546        receive_start(sender, content, we_started, request_handle, self, &self.state).await
1547    }
1548
1549    async fn start_sas(
1550        &self,
1551        we_started: bool,
1552        request_handle: RequestHandle,
1553    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1554        start_sas(self, &self.state, we_started, request_handle).await
1555    }
1556}
1557
1558impl Ready {
1559    fn to_transitioned<T: Clone>(
1560        &self,
1561        request_state: &RequestState<T>,
1562        verification: Verification,
1563    ) -> RequestState<Transitioned> {
1564        RequestState {
1565            verification_cache: request_state.verification_cache.to_owned(),
1566            store: request_state.store.to_owned(),
1567            flow_id: request_state.flow_id.to_owned(),
1568            other_user_id: request_state.other_user_id.to_owned(),
1569            state: Transitioned {
1570                ready: self.clone(),
1571                verification,
1572                other_device_data: self.other_device_data.clone(),
1573            },
1574        }
1575    }
1576}
1577
1578#[derive(Clone, Debug)]
1579struct Transitioned {
1580    ready: Ready,
1581    verification: Verification,
1582    other_device_data: DeviceData,
1583}
1584
1585impl RequestState<Transitioned> {
1586    #[cfg(feature = "qrcode")]
1587    async fn generate_qr_code(
1588        &self,
1589        we_started: bool,
1590        request_handle: RequestHandle,
1591    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1592        generate_qr_code(self, &self.state.ready, we_started, request_handle).await
1593    }
1594
1595    async fn receive_start(
1596        &self,
1597        sender: &UserId,
1598        content: &StartContent<'_>,
1599        we_started: bool,
1600        request_handle: RequestHandle,
1601    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1602        receive_start(sender, content, we_started, request_handle, self, &self.state.ready).await
1603    }
1604
1605    async fn start_sas(
1606        &self,
1607        we_started: bool,
1608        request_handle: RequestHandle,
1609    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1610        start_sas(self, &self.state.ready, we_started, request_handle).await
1611    }
1612}
1613
1614#[derive(Clone, Debug)]
1615struct Passive {
1616    /// The device ID of the device that responded to the verification request.
1617    #[allow(dead_code)]
1618    pub other_device_id: OwnedDeviceId,
1619}
1620
1621#[derive(Clone, Debug)]
1622struct Done {}
1623
1624#[cfg(test)]
1625mod tests {
1626
1627    use std::time::Duration;
1628
1629    use assert_matches::assert_matches;
1630    use assert_matches2::assert_let;
1631    #[cfg(feature = "qrcode")]
1632    use matrix_sdk_qrcode::QrVerificationData;
1633    use matrix_sdk_test::async_test;
1634    use ruma::{
1635        UserId, event_id, events::key::verification::VerificationMethod, room_id,
1636        to_device::DeviceIdOrAllDevices,
1637    };
1638
1639    use super::VerificationRequest;
1640    use crate::{
1641        DeviceData, VerificationRequestState,
1642        types::requests::OutgoingVerificationRequest,
1643        verification::{
1644            FlowId, Verification, VerificationStore,
1645            cache::VerificationCache,
1646            event_enums::{
1647                CancelContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
1648            },
1649            tests::{alice_id, bob_id, setup_stores},
1650        },
1651    };
1652
1653    #[async_test]
1654    async fn test_request_accepting() {
1655        let event_id = event_id!("$1234localhost").to_owned();
1656        let room_id = room_id!("!test:localhost").to_owned();
1657
1658        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1659
1660        let alice_device_data = DeviceData::from_account(&alice);
1661        let bob_device_data = DeviceData::from_account(&bob);
1662
1663        let content = VerificationRequest::request(
1664            &bob_store.account.user_id,
1665            &bob_store.account.device_id,
1666            alice_id(),
1667            None,
1668        );
1669
1670        let flow_id = FlowId::InRoom(room_id, event_id);
1671
1672        let bob_request = VerificationRequest::new(
1673            VerificationCache::new(),
1674            bob_store,
1675            flow_id.clone(),
1676            alice_id(),
1677            vec![],
1678            None,
1679        );
1680
1681        assert_matches!(bob_request.state(), VerificationRequestState::Created { .. });
1682        assert!(bob_request.time_remaining() <= Duration::from_secs(600)); // 10 minutes
1683        assert!(bob_request.time_remaining() > Duration::from_secs(540)); // 9 minutes
1684
1685        #[allow(clippy::needless_borrow)]
1686        let alice_request = VerificationRequest::from_request(
1687            VerificationCache::new(),
1688            alice_store,
1689            bob_id(),
1690            flow_id,
1691            &(&content).into(),
1692            bob_device_data,
1693        );
1694
1695        assert_matches!(alice_request.state(), VerificationRequestState::Requested { .. });
1696
1697        let content: OutgoingContent = alice_request.accept().unwrap().try_into().unwrap();
1698        let content = ReadyContent::try_from(&content).unwrap();
1699
1700        bob_request.receive_ready(alice_id(), &content, alice_device_data);
1701
1702        assert_matches!(bob_request.state(), VerificationRequestState::Ready { .. });
1703        assert_matches!(alice_request.state(), VerificationRequestState::Ready { .. });
1704        assert!(bob_request.is_ready());
1705        assert!(alice_request.is_ready());
1706    }
1707
1708    #[async_test]
1709    async fn test_request_refusal_to_device() {
1710        // test what happens when we cancel() a request that we have just received over
1711        // to-device messages.
1712        let (_alice, alice_store, bob, bob_store) = setup_stores().await;
1713        let bob_device = DeviceData::from_account(&bob);
1714
1715        // Set up the pair of verification requests
1716        let bob_request = build_test_request(&bob_store, alice_id(), None);
1717        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1718
1719        let outgoing_request = alice_request.cancel().unwrap();
1720
1721        // the outgoing message should target bob's device specifically
1722        {
1723            assert_let!(
1724                OutgoingVerificationRequest::ToDevice(to_device_request) = &outgoing_request
1725            );
1726
1727            assert_eq!(to_device_request.messages.len(), 1);
1728            let device_ids: Vec<&DeviceIdOrAllDevices> =
1729                to_device_request.messages.values().next().unwrap().keys().collect();
1730            assert_eq!(device_ids.len(), 1);
1731
1732            assert_let!(DeviceIdOrAllDevices::DeviceId(device_id) = &device_ids[0]);
1733            assert_eq!(device_id, bob_device.device_id());
1734        }
1735
1736        let content = OutgoingContent::try_from(outgoing_request).unwrap();
1737        let content = CancelContent::try_from(&content).unwrap();
1738
1739        bob_request.receive_cancel(alice_id(), &content);
1740
1741        assert_matches!(bob_request.state(), VerificationRequestState::Cancelled { .. });
1742        assert_matches!(alice_request.state(), VerificationRequestState::Cancelled { .. });
1743    }
1744
1745    #[async_test]
1746    async fn test_requesting_until_sas() {
1747        let event_id = event_id!("$1234localhost");
1748        let room_id = room_id!("!test:localhost");
1749
1750        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1751
1752        let alice_device_data = DeviceData::from_account(&alice);
1753        let bob_device_data = DeviceData::from_account(&bob);
1754
1755        let content = VerificationRequest::request(
1756            &bob_store.account.user_id,
1757            &bob_store.account.device_id,
1758            alice_id(),
1759            None,
1760        );
1761
1762        let flow_id = FlowId::from((room_id, event_id));
1763
1764        let bob_request = VerificationRequest::new(
1765            VerificationCache::new(),
1766            bob_store,
1767            flow_id.clone(),
1768            alice_id(),
1769            vec![],
1770            None,
1771        );
1772
1773        #[allow(clippy::needless_borrow)]
1774        let alice_request = VerificationRequest::from_request(
1775            VerificationCache::new(),
1776            alice_store,
1777            bob_id(),
1778            flow_id,
1779            &(&content).into(),
1780            bob_device_data.clone(),
1781        );
1782
1783        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1784
1785        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1786
1787        let content: OutgoingContent = request.try_into().unwrap();
1788        let content = StartContent::try_from(&content).unwrap();
1789        let flow_id = content.flow_id().to_owned();
1790        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1791        let alice_sas =
1792            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1793
1794        assert_let!(
1795            VerificationRequestState::Transitioned {
1796                verification: Verification::SasV1(_),
1797                other_device_data
1798            } = alice_request.state()
1799        );
1800
1801        assert_eq!(bob_device_data, other_device_data);
1802
1803        assert_let!(
1804            VerificationRequestState::Transitioned {
1805                verification: Verification::SasV1(_),
1806                other_device_data
1807            } = bob_request.state()
1808        );
1809
1810        assert_eq!(alice_device_data, other_device_data);
1811
1812        assert!(!bob_sas.is_cancelled());
1813        assert!(!alice_sas.is_cancelled());
1814    }
1815
1816    #[async_test]
1817    async fn test_requesting_until_sas_to_device() {
1818        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1819
1820        let alice_device_data = DeviceData::from_account(&alice);
1821        let bob_device_data = DeviceData::from_account(&bob);
1822
1823        // Set up the pair of verification requests
1824        let bob_request = build_test_request(&bob_store, alice_id(), None);
1825        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1826        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1827
1828        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1829
1830        let content: OutgoingContent = request.try_into().unwrap();
1831        let content = StartContent::try_from(&content).unwrap();
1832        let flow_id = content.flow_id().to_owned();
1833        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1834        let alice_sas =
1835            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1836
1837        assert_let!(
1838            VerificationRequestState::Transitioned {
1839                verification: Verification::SasV1(_),
1840                other_device_data
1841            } = alice_request.state()
1842        );
1843
1844        assert_eq!(bob_device_data, other_device_data);
1845
1846        assert_let!(
1847            VerificationRequestState::Transitioned {
1848                verification: Verification::SasV1(_),
1849                other_device_data
1850            } = bob_request.state()
1851        );
1852
1853        assert_eq!(alice_device_data, other_device_data);
1854
1855        assert!(!bob_sas.is_cancelled());
1856        assert!(!alice_sas.is_cancelled());
1857        assert!(alice_sas.started_from_request());
1858        assert!(bob_sas.started_from_request());
1859    }
1860
1861    #[async_test]
1862    #[cfg(feature = "qrcode")]
1863    async fn test_can_scan_another_qr_after_creating_mine() {
1864        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1865
1866        let alice_device_data = DeviceData::from_account(&alice);
1867        let bob_device_data = DeviceData::from_account(&bob);
1868
1869        // Set up the pair of verification requests
1870        let bob_request = build_test_request(
1871            &bob_store,
1872            alice_id(),
1873            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1874        );
1875        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1876        do_accept_request(
1877            &alice_request,
1878            alice_device_data.clone(),
1879            &bob_request,
1880            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1881        );
1882
1883        // Each side can start its own QR verification flow by generating QR code
1884        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1885        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1886
1887        assert_let!(
1888            VerificationRequestState::Transitioned {
1889                verification: Verification::QrV1(_),
1890                other_device_data
1891            } = alice_request.state()
1892        );
1893
1894        assert_eq!(bob_device_data, other_device_data);
1895
1896        assert_let!(
1897            VerificationRequestState::Transitioned {
1898                verification: Verification::QrV1(_),
1899                other_device_data
1900            } = bob_request.state()
1901        );
1902
1903        assert_eq!(alice_device_data, other_device_data);
1904
1905        assert!(alice_verification.is_some());
1906        assert!(bob_verification.is_some());
1907
1908        // Now only Alice scans Bob's code
1909        let bob_qr_code = bob_verification.unwrap().to_bytes().unwrap();
1910        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
1911        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
1912
1913        assert_let!(
1914            VerificationRequestState::Transitioned {
1915                verification: Verification::QrV1(alice_verification),
1916                other_device_data
1917            } = alice_request.state()
1918        );
1919
1920        assert_eq!(bob_device_data, other_device_data);
1921
1922        // Finally we assert that the verification has been reciprocated rather than
1923        // cancelled due to a duplicate verification flow
1924        assert!(!alice_verification.is_cancelled());
1925        assert!(alice_verification.reciprocated());
1926    }
1927
1928    #[async_test]
1929    #[cfg(feature = "qrcode")]
1930    async fn test_can_start_sas_after_generating_qr_code() {
1931        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1932
1933        let alice_device_data = DeviceData::from_account(&alice);
1934        let bob_device_data = DeviceData::from_account(&bob);
1935
1936        // Set up the pair of verification requests
1937        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
1938        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1939        do_accept_request(
1940            &alice_request,
1941            alice_device_data.clone(),
1942            &bob_request,
1943            Some(all_methods()),
1944        );
1945
1946        // Each side can start its own QR verification flow by generating QR code
1947        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1948        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1949
1950        assert_let!(
1951            VerificationRequestState::Transitioned {
1952                verification: Verification::QrV1(_),
1953                other_device_data
1954            } = alice_request.state()
1955        );
1956
1957        assert_eq!(bob_device_data, other_device_data);
1958
1959        assert!(alice_verification.is_some());
1960        assert!(bob_verification.is_some());
1961
1962        // Alice can now start SAS verification flow instead of QR without cancelling
1963        // the request
1964        let (sas, request) = alice_request.start_sas().await.unwrap().unwrap();
1965        assert_let!(
1966            VerificationRequestState::Transitioned {
1967                verification: Verification::SasV1(_),
1968                other_device_data
1969            } = alice_request.state()
1970        );
1971
1972        assert_eq!(bob_device_data, other_device_data);
1973        assert!(!sas.is_cancelled());
1974
1975        // Bob receives the SAS start
1976        let content: OutgoingContent = request.try_into().unwrap();
1977        let content = StartContent::try_from(&content).unwrap();
1978        bob_request.receive_start(alice_id(), &content).await.unwrap();
1979
1980        // Bob should now have transitioned to SAS...
1981        assert_let!(
1982            VerificationRequestState::Transitioned {
1983                verification: Verification::SasV1(bob_sas),
1984                other_device_data
1985            } = bob_request.state()
1986        );
1987
1988        assert_eq!(alice_device_data, other_device_data);
1989
1990        // ... and, more to the point, it should not be cancelled.
1991        assert!(!bob_sas.is_cancelled());
1992    }
1993
1994    #[async_test]
1995    #[cfg(feature = "qrcode")]
1996    async fn test_start_sas_after_scan_cancels_request() {
1997        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1998
1999        let alice_device_data = DeviceData::from_account(&alice);
2000        let bob_device_data = DeviceData::from_account(&bob);
2001
2002        // Set up the pair of verification requests
2003        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
2004        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
2005        do_accept_request(
2006            &alice_request,
2007            alice_device_data.clone(),
2008            &bob_request,
2009            Some(all_methods()),
2010        );
2011
2012        // Bob generates a QR code
2013        let bob_verification = bob_request.generate_qr_code().await.unwrap().unwrap();
2014        assert_let!(
2015            VerificationRequestState::Transitioned {
2016                verification: Verification::QrV1(_),
2017                other_device_data
2018            } = bob_request.state()
2019        );
2020
2021        assert_eq!(alice_device_data, other_device_data);
2022
2023        // Now Alice scans Bob's code
2024        let bob_qr_code = bob_verification.to_bytes().unwrap();
2025        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
2026        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
2027
2028        assert_let!(
2029            VerificationRequestState::Transitioned {
2030                verification: Verification::QrV1(alice_qr),
2031                other_device_data
2032            } = alice_request.state()
2033        );
2034
2035        assert_eq!(bob_device_data, other_device_data);
2036        assert!(alice_qr.reciprocated());
2037
2038        // But Bob wants to do an SAS verification!
2039        let (_, request) = bob_request.start_sas().await.unwrap().unwrap();
2040        assert_let!(
2041            VerificationRequestState::Transitioned {
2042                verification: Verification::SasV1(_),
2043                other_device_data
2044            } = bob_request.state()
2045        );
2046
2047        assert_eq!(alice_device_data, other_device_data);
2048
2049        // Alice receives the SAS start
2050        let content: OutgoingContent = request.try_into().unwrap();
2051        let content = StartContent::try_from(&content).unwrap();
2052        alice_request.receive_start(bob_id(), &content).await.unwrap();
2053
2054        // ... which should mean that her Qr is cancelled
2055        assert!(alice_qr.is_cancelled());
2056
2057        // and she should now have a *cancelled* SAS verification
2058        assert_let!(
2059            VerificationRequestState::Transitioned {
2060                verification: Verification::SasV1(alice_sas),
2061                other_device_data
2062            } = alice_request.state()
2063        );
2064
2065        assert_eq!(bob_device_data, other_device_data);
2066        assert!(alice_sas.is_cancelled());
2067    }
2068
2069    /// Build an outgoing Verification request
2070    ///
2071    /// # Arguments
2072    ///
2073    /// * `verification_store` - The `VerificationStore` for the user making the
2074    ///   request.
2075    /// * `other_user_id` - The ID of the user we want to verify
2076    /// * `methods` - A list of `VerificationMethods` to say we support. If
2077    ///   `None`, will use the default list.
2078    fn build_test_request(
2079        verification_store: &VerificationStore,
2080        other_user_id: &UserId,
2081        methods: Option<Vec<VerificationMethod>>,
2082    ) -> VerificationRequest {
2083        VerificationRequest::new(
2084            VerificationCache::new(),
2085            verification_store.clone(),
2086            FlowId::ToDevice("TEST_FLOW_ID".into()),
2087            other_user_id,
2088            vec![],
2089            methods,
2090        )
2091    }
2092
2093    /// Given an outgoing `VerificationRequest`, create an incoming
2094    /// `VerificationRequest` for the other side.
2095    ///
2096    /// Tells the outgoing request to generate an `m.key.verification.request`
2097    /// to-device message, and uses it to build a new request for the incoming
2098    /// side.
2099    async fn build_incoming_verification_request(
2100        verification_store: &VerificationStore,
2101        outgoing_request: &VerificationRequest,
2102    ) -> VerificationRequest {
2103        let request = outgoing_request.request_to_device();
2104        let content: OutgoingContent = request.try_into().unwrap();
2105        let content = RequestContent::try_from(&content).unwrap();
2106
2107        let device_data = verification_store
2108            .get_device(outgoing_request.own_user_id(), content.from_device())
2109            .await
2110            .unwrap()
2111            .expect("Missing device data");
2112
2113        VerificationRequest::from_request(
2114            VerificationCache::new(),
2115            verification_store.clone(),
2116            outgoing_request.own_user_id(),
2117            outgoing_request.flow_id().clone(),
2118            &content,
2119            device_data,
2120        )
2121    }
2122
2123    /// Have a `VerificationRequest` generate an `m.key.verification.ready` and
2124    /// feed it into another `VerificationRequest`.
2125    ///
2126    /// # Arguments
2127    ///
2128    /// * `accepting_request` - The request which should send the acceptance.
2129    /// * `initiating_request` - The request which initiated the flow -- i.e.,
2130    ///   the one that should *receive* the acceptance.
2131    /// * `methods` - The list of methods to say we support. If `None`, the
2132    ///   default list of methods will be used.
2133    fn do_accept_request(
2134        accepting_request: &VerificationRequest,
2135        accepting_device_data: DeviceData,
2136        initiating_request: &VerificationRequest,
2137        methods: Option<Vec<VerificationMethod>>,
2138    ) {
2139        let request = match methods {
2140            Some(methods) => accepting_request.accept_with_methods(methods),
2141            None => accepting_request.accept(),
2142        };
2143        let content: OutgoingContent = request.unwrap().try_into().unwrap();
2144        let content = ReadyContent::try_from(&content).unwrap();
2145        initiating_request.receive_ready(
2146            accepting_request.own_user_id(),
2147            &content,
2148            accepting_device_data,
2149        );
2150
2151        assert!(initiating_request.is_ready());
2152        assert!(accepting_request.is_ready());
2153    }
2154
2155    /// Get a list of all the verification methods, including those used for QR
2156    /// codes.
2157    #[cfg(feature = "qrcode")]
2158    fn all_methods() -> Vec<VerificationMethod> {
2159        vec![
2160            VerificationMethod::SasV1,
2161            VerificationMethod::QrCodeScanV1,
2162            VerificationMethod::QrCodeShowV1,
2163            VerificationMethod::ReciprocateV1,
2164        ]
2165    }
2166}