Skip to main content

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