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_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 side
1223    // 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 identity
1278                    // if we don't have the private one and we trust the public
1279                    // 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
1382                            // already started one before the other side tried
1383                            // to do the same; ignore it if we did and we're the
1384                            // lexicographically smaller user ID (or device ID
1385                            // if equal).
1386                            use std::cmp::Ordering;
1387                            if !matches!(
1388                                (
1389                                    sender.cmp(own_user_id),
1390                                    other_device_data.device_id().cmp(own_device_id)
1391                                ),
1392                                (Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater)
1393                            ) {
1394                                info!(
1395                                    "Started a new SAS verification, replacing an already started one."
1396                                );
1397                                request_state.verification_cache.replace_sas(new.to_owned());
1398                                Ok(Some(state.to_transitioned(request_state, new.into())))
1399                            } else {
1400                                info!(
1401                                    "Ignored incoming SAS verification from lexicographically larger user/device ID."
1402                                );
1403                                Ok(None)
1404                            }
1405                        }
1406                        #[cfg(feature = "qrcode")]
1407                        Some(Verification::QrV1(old)) => {
1408                            // If there is already a QR verification, our
1409                            // ability to transition to SAS depends on how far
1410                            // we got through the QR flow.
1411                            if let QrVerificationState::Started = old.state() {
1412                                // it is legit to transition from QR display to
1413                                // SAS
1414                                info!("Transitioned from QR display to SAS");
1415                                request_state.verification_cache.replace_sas(new.to_owned());
1416                                Ok(Some(state.to_transitioned(request_state, new.into())))
1417                            } else {
1418                                // otherwise, we've either scanned their QR
1419                                // code, or they have scanned ours -- i.e., an
1420                                // `m.key.verification.start` with method
1421                                // `m.reciprocate.v1` has already been
1422                                // sent/received and, per the spec, it is too
1423                                // late to switch to SAS.
1424                                warn!(qr_state = ?old.state(), "Invalid transition from QR to SAS");
1425                                request_state.verification_cache.insert_sas(new.to_owned());
1426                                Ok(Some(state.to_transitioned(request_state, new.into())))
1427                            }
1428                        }
1429                        None => {
1430                            info!("Started a new SAS verification.");
1431                            request_state.verification_cache.insert_sas(new.to_owned());
1432                            Ok(Some(state.to_transitioned(request_state, new.into())))
1433                        }
1434                    }
1435                }
1436                Err(c) => {
1437                    warn!(
1438                        user_id = ?other_device_data.user_id(),
1439                        device_id = ?other_device_data.device_id(),
1440                        content = ?c,
1441                        "Can't start key verification, canceling.",
1442                    );
1443                    request_state.verification_cache.queue_up_content(
1444                        other_device_data.user_id(),
1445                        other_device_data.device_id(),
1446                        c,
1447                        None,
1448                    );
1449
1450                    Ok(None)
1451                }
1452            }
1453        }
1454        #[cfg(feature = "qrcode")]
1455        StartMethod::ReciprocateV1(_) => {
1456            if let Some(qr_verification) =
1457                request_state.verification_cache.get_qr(sender, content.flow_id())
1458            {
1459                if let Some(request) = qr_verification.receive_reciprocation(content) {
1460                    request_state.verification_cache.add_request(request.into())
1461                }
1462                debug!(
1463                    sender = ?identities.device_being_verified.user_id(),
1464                    device_id = ?identities.device_being_verified.device_id(),
1465                    verification = ?qr_verification,
1466                    "Received a QR code reciprocation"
1467                );
1468
1469                Ok(None)
1470            } else {
1471                warn!("Received a QR code reciprocation for an unknown flow");
1472                Ok(None)
1473            }
1474        }
1475        m => {
1476            warn!(method = ?m, "Received a key verification start event with an unsupported method");
1477            Ok(None)
1478        }
1479    }
1480}
1481
1482async fn start_sas<T: Clone>(
1483    request_state: &RequestState<T>,
1484    state: &Ready,
1485    we_started: bool,
1486    request_handle: RequestHandle,
1487) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1488    if !state.their_methods.contains(&VerificationMethod::SasV1) {
1489        return Ok(None);
1490    }
1491
1492    let identities = request_state.store.get_identities(state.other_device_data.clone()).await?;
1493
1494    let (state, sas, content) = match request_state.flow_id.as_ref() {
1495        FlowId::ToDevice(t) => {
1496            let (sas, content) =
1497                Sas::start(identities, t.to_owned(), we_started, Some(request_handle), None);
1498
1499            let state = Transitioned {
1500                ready: state.to_owned(),
1501                verification: sas.to_owned().into(),
1502                other_device_data: state.other_device_data.to_owned(),
1503            };
1504
1505            (state, sas, content)
1506        }
1507        FlowId::InRoom(r, e) => {
1508            let (sas, content) = Sas::start_in_room(
1509                e.to_owned(),
1510                r.to_owned(),
1511                identities,
1512                we_started,
1513                request_handle,
1514            );
1515            let state = Transitioned {
1516                ready: state.to_owned(),
1517                verification: sas.to_owned().into(),
1518                other_device_data: state.other_device_data.to_owned(),
1519            };
1520            (state, sas, content)
1521        }
1522    };
1523
1524    let state = RequestState {
1525        verification_cache: request_state.verification_cache.to_owned(),
1526        store: request_state.store.to_owned(),
1527        flow_id: request_state.flow_id.to_owned(),
1528        other_user_id: request_state.other_user_id.to_owned(),
1529        state,
1530    };
1531
1532    Ok(Some((state, sas, content)))
1533}
1534
1535impl RequestState<Ready> {
1536    #[cfg(feature = "qrcode")]
1537    async fn generate_qr_code(
1538        &self,
1539        we_started: bool,
1540        request_handle: RequestHandle,
1541    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1542        generate_qr_code(self, &self.state, we_started, request_handle).await
1543    }
1544
1545    async fn receive_start(
1546        &self,
1547        sender: &UserId,
1548        content: &StartContent<'_>,
1549        we_started: bool,
1550        request_handle: RequestHandle,
1551    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1552        receive_start(sender, content, we_started, request_handle, self, &self.state).await
1553    }
1554
1555    async fn start_sas(
1556        &self,
1557        we_started: bool,
1558        request_handle: RequestHandle,
1559    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1560        start_sas(self, &self.state, we_started, request_handle).await
1561    }
1562}
1563
1564impl Ready {
1565    fn to_transitioned<T: Clone>(
1566        &self,
1567        request_state: &RequestState<T>,
1568        verification: Verification,
1569    ) -> RequestState<Transitioned> {
1570        RequestState {
1571            verification_cache: request_state.verification_cache.to_owned(),
1572            store: request_state.store.to_owned(),
1573            flow_id: request_state.flow_id.to_owned(),
1574            other_user_id: request_state.other_user_id.to_owned(),
1575            state: Transitioned {
1576                ready: self.clone(),
1577                verification,
1578                other_device_data: self.other_device_data.clone(),
1579            },
1580        }
1581    }
1582}
1583
1584#[derive(Clone, Debug)]
1585struct Transitioned {
1586    ready: Ready,
1587    verification: Verification,
1588    other_device_data: DeviceData,
1589}
1590
1591impl RequestState<Transitioned> {
1592    #[cfg(feature = "qrcode")]
1593    async fn generate_qr_code(
1594        &self,
1595        we_started: bool,
1596        request_handle: RequestHandle,
1597    ) -> Result<Option<(RequestState<Transitioned>, QrVerification)>, CryptoStoreError> {
1598        generate_qr_code(self, &self.state.ready, we_started, request_handle).await
1599    }
1600
1601    async fn receive_start(
1602        &self,
1603        sender: &UserId,
1604        content: &StartContent<'_>,
1605        we_started: bool,
1606        request_handle: RequestHandle,
1607    ) -> Result<Option<RequestState<Transitioned>>, CryptoStoreError> {
1608        receive_start(sender, content, we_started, request_handle, self, &self.state.ready).await
1609    }
1610
1611    async fn start_sas(
1612        &self,
1613        we_started: bool,
1614        request_handle: RequestHandle,
1615    ) -> Result<Option<(RequestState<Transitioned>, Sas, OutgoingContent)>, CryptoStoreError> {
1616        start_sas(self, &self.state.ready, we_started, request_handle).await
1617    }
1618}
1619
1620#[derive(Clone, Debug)]
1621struct Passive {
1622    /// The device ID of the device that responded to the verification request.
1623    #[allow(dead_code)]
1624    pub other_device_id: OwnedDeviceId,
1625}
1626
1627#[derive(Clone, Debug)]
1628struct Done {}
1629
1630#[cfg(test)]
1631mod tests {
1632
1633    use std::time::Duration;
1634
1635    use assert_matches::assert_matches;
1636    #[cfg(feature = "qrcode")]
1637    use matrix_sdk_qrcode::QrVerificationData;
1638    use matrix_sdk_test::async_test;
1639    use ruma::{
1640        UserId, event_id, events::key::verification::VerificationMethod, owned_event_id,
1641        owned_room_id, room_id, to_device::DeviceIdOrAllDevices,
1642    };
1643    use strass::assert_let;
1644
1645    use super::VerificationRequest;
1646    use crate::{
1647        DeviceData, VerificationRequestState,
1648        types::requests::OutgoingVerificationRequest,
1649        verification::{
1650            FlowId, Verification, VerificationStore,
1651            cache::VerificationCache,
1652            event_enums::{
1653                CancelContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
1654            },
1655            tests::{alice_id, bob_id, setup_stores},
1656        },
1657    };
1658
1659    #[async_test]
1660    async fn test_request_accepting() {
1661        let event_id = owned_event_id!("$1234localhost");
1662        let room_id = owned_room_id!("!test:localhost");
1663
1664        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1665
1666        let alice_device_data = DeviceData::from_account(&alice);
1667        let bob_device_data = DeviceData::from_account(&bob);
1668
1669        let content = VerificationRequest::request(
1670            &bob_store.account.user_id,
1671            &bob_store.account.device_id,
1672            alice_id(),
1673            None,
1674        );
1675
1676        let flow_id = FlowId::InRoom(room_id, event_id);
1677
1678        let bob_request = VerificationRequest::new(
1679            VerificationCache::new(),
1680            bob_store,
1681            flow_id.clone(),
1682            alice_id(),
1683            vec![],
1684            None,
1685        );
1686
1687        assert_matches!(bob_request.state(), VerificationRequestState::Created { .. });
1688        assert!(bob_request.time_remaining() <= Duration::from_secs(600)); // 10 minutes
1689        assert!(bob_request.time_remaining() > Duration::from_secs(540)); // 9 minutes
1690
1691        #[allow(clippy::needless_borrow)]
1692        let alice_request = VerificationRequest::from_request(
1693            VerificationCache::new(),
1694            alice_store,
1695            bob_id(),
1696            flow_id,
1697            &(&content).into(),
1698            bob_device_data,
1699        );
1700
1701        assert_matches!(alice_request.state(), VerificationRequestState::Requested { .. });
1702
1703        let content: OutgoingContent = alice_request.accept().unwrap().try_into().unwrap();
1704        let content = ReadyContent::try_from(&content).unwrap();
1705
1706        bob_request.receive_ready(alice_id(), &content, alice_device_data);
1707
1708        assert_matches!(bob_request.state(), VerificationRequestState::Ready { .. });
1709        assert_matches!(alice_request.state(), VerificationRequestState::Ready { .. });
1710        assert!(bob_request.is_ready());
1711        assert!(alice_request.is_ready());
1712    }
1713
1714    #[async_test]
1715    async fn test_request_refusal_to_device() {
1716        // test what happens when we cancel() a request that we have just
1717        // received over to-device messages.
1718        let (_alice, alice_store, bob, bob_store) = setup_stores().await;
1719        let bob_device = DeviceData::from_account(&bob);
1720
1721        // Set up the pair of verification requests
1722        let bob_request = build_test_request(&bob_store, alice_id(), None);
1723        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1724
1725        let outgoing_request = alice_request.cancel().unwrap();
1726
1727        // the outgoing message should target bob's device specifically
1728        {
1729            assert_let!(
1730                OutgoingVerificationRequest::ToDevice(to_device_request) = &outgoing_request
1731            );
1732
1733            assert_eq!(to_device_request.messages.len(), 1);
1734            let device_ids: Vec<&DeviceIdOrAllDevices> =
1735                to_device_request.messages.values().next().unwrap().keys().collect();
1736            assert_eq!(device_ids.len(), 1);
1737
1738            assert_let!(DeviceIdOrAllDevices::DeviceId(device_id) = &device_ids[0]);
1739            assert_eq!(device_id, bob_device.device_id());
1740        }
1741
1742        let content = OutgoingContent::try_from(outgoing_request).unwrap();
1743        let content = CancelContent::try_from(&content).unwrap();
1744
1745        bob_request.receive_cancel(alice_id(), &content);
1746
1747        assert_matches!(bob_request.state(), VerificationRequestState::Cancelled { .. });
1748        assert_matches!(alice_request.state(), VerificationRequestState::Cancelled { .. });
1749    }
1750
1751    #[async_test]
1752    async fn test_requesting_until_sas() {
1753        let event_id = event_id!("$1234localhost");
1754        let room_id = room_id!("!test:localhost");
1755
1756        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1757
1758        let alice_device_data = DeviceData::from_account(&alice);
1759        let bob_device_data = DeviceData::from_account(&bob);
1760
1761        let content = VerificationRequest::request(
1762            &bob_store.account.user_id,
1763            &bob_store.account.device_id,
1764            alice_id(),
1765            None,
1766        );
1767
1768        let flow_id = FlowId::from((room_id, event_id));
1769
1770        let bob_request = VerificationRequest::new(
1771            VerificationCache::new(),
1772            bob_store,
1773            flow_id.clone(),
1774            alice_id(),
1775            vec![],
1776            None,
1777        );
1778
1779        #[allow(clippy::needless_borrow)]
1780        let alice_request = VerificationRequest::from_request(
1781            VerificationCache::new(),
1782            alice_store,
1783            bob_id(),
1784            flow_id,
1785            &(&content).into(),
1786            bob_device_data.clone(),
1787        );
1788
1789        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1790
1791        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1792
1793        let content: OutgoingContent = request.try_into().unwrap();
1794        let content = StartContent::try_from(&content).unwrap();
1795        let flow_id = content.flow_id().to_owned();
1796        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1797        let alice_sas =
1798            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1799
1800        assert_let!(
1801            VerificationRequestState::Transitioned {
1802                verification: Verification::SasV1(_),
1803                other_device_data
1804            } = alice_request.state()
1805        );
1806
1807        assert_eq!(bob_device_data, other_device_data);
1808
1809        assert_let!(
1810            VerificationRequestState::Transitioned {
1811                verification: Verification::SasV1(_),
1812                other_device_data
1813            } = bob_request.state()
1814        );
1815
1816        assert_eq!(alice_device_data, other_device_data);
1817
1818        assert!(!bob_sas.is_cancelled());
1819        assert!(!alice_sas.is_cancelled());
1820    }
1821
1822    #[async_test]
1823    async fn test_requesting_until_sas_to_device() {
1824        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1825
1826        let alice_device_data = DeviceData::from_account(&alice);
1827        let bob_device_data = DeviceData::from_account(&bob);
1828
1829        // Set up the pair of verification requests
1830        let bob_request = build_test_request(&bob_store, alice_id(), None);
1831        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1832        do_accept_request(&alice_request, alice_device_data.clone(), &bob_request, None);
1833
1834        let (bob_sas, request) = bob_request.start_sas().await.unwrap().unwrap();
1835
1836        let content: OutgoingContent = request.try_into().unwrap();
1837        let content = StartContent::try_from(&content).unwrap();
1838        let flow_id = content.flow_id().to_owned();
1839        alice_request.receive_start(bob_device_data.user_id(), &content).await.unwrap();
1840        let alice_sas =
1841            alice_request.verification_cache.get_sas(bob_device_data.user_id(), &flow_id).unwrap();
1842
1843        assert_let!(
1844            VerificationRequestState::Transitioned {
1845                verification: Verification::SasV1(_),
1846                other_device_data
1847            } = alice_request.state()
1848        );
1849
1850        assert_eq!(bob_device_data, other_device_data);
1851
1852        assert_let!(
1853            VerificationRequestState::Transitioned {
1854                verification: Verification::SasV1(_),
1855                other_device_data
1856            } = bob_request.state()
1857        );
1858
1859        assert_eq!(alice_device_data, other_device_data);
1860
1861        assert!(!bob_sas.is_cancelled());
1862        assert!(!alice_sas.is_cancelled());
1863        assert!(alice_sas.started_from_request());
1864        assert!(bob_sas.started_from_request());
1865    }
1866
1867    #[async_test]
1868    #[cfg(feature = "qrcode")]
1869    async fn test_can_scan_another_qr_after_creating_mine() {
1870        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1871
1872        let alice_device_data = DeviceData::from_account(&alice);
1873        let bob_device_data = DeviceData::from_account(&bob);
1874
1875        // Set up the pair of verification requests
1876        let bob_request = build_test_request(
1877            &bob_store,
1878            alice_id(),
1879            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1880        );
1881        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1882        do_accept_request(
1883            &alice_request,
1884            alice_device_data.clone(),
1885            &bob_request,
1886            Some(vec![VerificationMethod::QrCodeScanV1, VerificationMethod::QrCodeShowV1]),
1887        );
1888
1889        // Each side can start its own QR verification flow by generating QR
1890        // code
1891        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1892        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1893
1894        assert_let!(
1895            VerificationRequestState::Transitioned {
1896                verification: Verification::QrV1(_),
1897                other_device_data
1898            } = alice_request.state()
1899        );
1900
1901        assert_eq!(bob_device_data, other_device_data);
1902
1903        assert_let!(
1904            VerificationRequestState::Transitioned {
1905                verification: Verification::QrV1(_),
1906                other_device_data
1907            } = bob_request.state()
1908        );
1909
1910        assert_eq!(alice_device_data, other_device_data);
1911
1912        assert!(alice_verification.is_some());
1913        assert!(bob_verification.is_some());
1914
1915        // Now only Alice scans Bob's code
1916        let bob_qr_code = bob_verification.unwrap().to_bytes().unwrap();
1917        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
1918        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
1919
1920        assert_let!(
1921            VerificationRequestState::Transitioned {
1922                verification: Verification::QrV1(alice_verification),
1923                other_device_data
1924            } = alice_request.state()
1925        );
1926
1927        assert_eq!(bob_device_data, other_device_data);
1928
1929        // Finally we assert that the verification has been reciprocated rather
1930        // than cancelled due to a duplicate verification flow
1931        assert!(!alice_verification.is_cancelled());
1932        assert!(alice_verification.reciprocated());
1933    }
1934
1935    #[async_test]
1936    #[cfg(feature = "qrcode")]
1937    async fn test_can_start_sas_after_generating_qr_code() {
1938        let (alice, alice_store, bob, bob_store) = setup_stores().await;
1939
1940        let alice_device_data = DeviceData::from_account(&alice);
1941        let bob_device_data = DeviceData::from_account(&bob);
1942
1943        // Set up the pair of verification requests
1944        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
1945        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
1946        do_accept_request(
1947            &alice_request,
1948            alice_device_data.clone(),
1949            &bob_request,
1950            Some(all_methods()),
1951        );
1952
1953        // Each side can start its own QR verification flow by generating QR
1954        // code
1955        let alice_verification = alice_request.generate_qr_code().await.unwrap();
1956        let bob_verification = bob_request.generate_qr_code().await.unwrap();
1957
1958        assert_let!(
1959            VerificationRequestState::Transitioned {
1960                verification: Verification::QrV1(_),
1961                other_device_data
1962            } = alice_request.state()
1963        );
1964
1965        assert_eq!(bob_device_data, other_device_data);
1966
1967        assert!(alice_verification.is_some());
1968        assert!(bob_verification.is_some());
1969
1970        // Alice can now start SAS verification flow instead of QR without
1971        // cancelling the request
1972        let (sas, request) = alice_request.start_sas().await.unwrap().unwrap();
1973        assert_let!(
1974            VerificationRequestState::Transitioned {
1975                verification: Verification::SasV1(_),
1976                other_device_data
1977            } = alice_request.state()
1978        );
1979
1980        assert_eq!(bob_device_data, other_device_data);
1981        assert!(!sas.is_cancelled());
1982
1983        // Bob receives the SAS start
1984        let content: OutgoingContent = request.try_into().unwrap();
1985        let content = StartContent::try_from(&content).unwrap();
1986        bob_request.receive_start(alice_id(), &content).await.unwrap();
1987
1988        // Bob should now have transitioned to SAS...
1989        assert_let!(
1990            VerificationRequestState::Transitioned {
1991                verification: Verification::SasV1(bob_sas),
1992                other_device_data
1993            } = bob_request.state()
1994        );
1995
1996        assert_eq!(alice_device_data, other_device_data);
1997
1998        // ... and, more to the point, it should not be cancelled.
1999        assert!(!bob_sas.is_cancelled());
2000    }
2001
2002    #[async_test]
2003    #[cfg(feature = "qrcode")]
2004    async fn test_start_sas_after_scan_cancels_request() {
2005        let (alice, alice_store, bob, bob_store) = setup_stores().await;
2006
2007        let alice_device_data = DeviceData::from_account(&alice);
2008        let bob_device_data = DeviceData::from_account(&bob);
2009
2010        // Set up the pair of verification requests
2011        let bob_request = build_test_request(&bob_store, alice_id(), Some(all_methods()));
2012        let alice_request = build_incoming_verification_request(&alice_store, &bob_request).await;
2013        do_accept_request(
2014            &alice_request,
2015            alice_device_data.clone(),
2016            &bob_request,
2017            Some(all_methods()),
2018        );
2019
2020        // Bob generates a QR code
2021        let bob_verification = bob_request.generate_qr_code().await.unwrap().unwrap();
2022        assert_let!(
2023            VerificationRequestState::Transitioned {
2024                verification: Verification::QrV1(_),
2025                other_device_data
2026            } = bob_request.state()
2027        );
2028
2029        assert_eq!(alice_device_data, other_device_data);
2030
2031        // Now Alice scans Bob's code
2032        let bob_qr_code = bob_verification.to_bytes().unwrap();
2033        let bob_qr_code = QrVerificationData::from_bytes(bob_qr_code).unwrap();
2034        let _ = alice_request.scan_qr_code(bob_qr_code).await.unwrap().unwrap();
2035
2036        assert_let!(
2037            VerificationRequestState::Transitioned {
2038                verification: Verification::QrV1(alice_qr),
2039                other_device_data
2040            } = alice_request.state()
2041        );
2042
2043        assert_eq!(bob_device_data, other_device_data);
2044        assert!(alice_qr.reciprocated());
2045
2046        // But Bob wants to do an SAS verification!
2047        let (_, request) = bob_request.start_sas().await.unwrap().unwrap();
2048        assert_let!(
2049            VerificationRequestState::Transitioned {
2050                verification: Verification::SasV1(_),
2051                other_device_data
2052            } = bob_request.state()
2053        );
2054
2055        assert_eq!(alice_device_data, other_device_data);
2056
2057        // Alice receives the SAS start
2058        let content: OutgoingContent = request.try_into().unwrap();
2059        let content = StartContent::try_from(&content).unwrap();
2060        alice_request.receive_start(bob_id(), &content).await.unwrap();
2061
2062        // ... which should mean that her Qr is cancelled
2063        assert!(alice_qr.is_cancelled());
2064
2065        // and she should now have a *cancelled* SAS verification
2066        assert_let!(
2067            VerificationRequestState::Transitioned {
2068                verification: Verification::SasV1(alice_sas),
2069                other_device_data
2070            } = alice_request.state()
2071        );
2072
2073        assert_eq!(bob_device_data, other_device_data);
2074        assert!(alice_sas.is_cancelled());
2075    }
2076
2077    /// Build an outgoing Verification request
2078    ///
2079    /// # Arguments
2080    ///
2081    /// - `verification_store` - The `VerificationStore` for the user making the
2082    ///   request.
2083    /// - `other_user_id` - The ID of the user we want to verify
2084    /// - `methods` - A list of `VerificationMethods` to say we support. If
2085    ///   `None`, will use the default list.
2086    fn build_test_request(
2087        verification_store: &VerificationStore,
2088        other_user_id: &UserId,
2089        methods: Option<Vec<VerificationMethod>>,
2090    ) -> VerificationRequest {
2091        VerificationRequest::new(
2092            VerificationCache::new(),
2093            verification_store.clone(),
2094            FlowId::ToDevice("TEST_FLOW_ID".into()),
2095            other_user_id,
2096            vec![],
2097            methods,
2098        )
2099    }
2100
2101    /// Given an outgoing `VerificationRequest`, create an incoming
2102    /// `VerificationRequest` for the other side.
2103    ///
2104    /// Tells the outgoing request to generate an `m.key.verification.request`
2105    /// to-device message, and uses it to build a new request for the incoming
2106    /// side.
2107    async fn build_incoming_verification_request(
2108        verification_store: &VerificationStore,
2109        outgoing_request: &VerificationRequest,
2110    ) -> VerificationRequest {
2111        let request = outgoing_request.request_to_device();
2112        let content: OutgoingContent = request.try_into().unwrap();
2113        let content = RequestContent::try_from(&content).unwrap();
2114
2115        let device_data = verification_store
2116            .get_device(outgoing_request.own_user_id(), content.from_device())
2117            .await
2118            .unwrap()
2119            .expect("Missing device data");
2120
2121        VerificationRequest::from_request(
2122            VerificationCache::new(),
2123            verification_store.clone(),
2124            outgoing_request.own_user_id(),
2125            outgoing_request.flow_id().clone(),
2126            &content,
2127            device_data,
2128        )
2129    }
2130
2131    /// Have a `VerificationRequest` generate an `m.key.verification.ready` and
2132    /// feed it into another `VerificationRequest`.
2133    ///
2134    /// # Arguments
2135    ///
2136    /// - `accepting_request` - The request which should send the acceptance.
2137    /// - `initiating_request` - The request which initiated the flow -- i.e.,
2138    ///   the one that should _receive_ the acceptance.
2139    /// - `methods` - The list of methods to say we support. If `None`, the
2140    ///   default list of methods will be used.
2141    fn do_accept_request(
2142        accepting_request: &VerificationRequest,
2143        accepting_device_data: DeviceData,
2144        initiating_request: &VerificationRequest,
2145        methods: Option<Vec<VerificationMethod>>,
2146    ) {
2147        let request = match methods {
2148            Some(methods) => accepting_request.accept_with_methods(methods),
2149            None => accepting_request.accept(),
2150        };
2151        let content: OutgoingContent = request.unwrap().try_into().unwrap();
2152        let content = ReadyContent::try_from(&content).unwrap();
2153        initiating_request.receive_ready(
2154            accepting_request.own_user_id(),
2155            &content,
2156            accepting_device_data,
2157        );
2158
2159        assert!(initiating_request.is_ready());
2160        assert!(accepting_request.is_ready());
2161    }
2162
2163    /// Get a list of all the verification methods, including those used for QR
2164    /// codes.
2165    #[cfg(feature = "qrcode")]
2166    fn all_methods() -> Vec<VerificationMethod> {
2167        vec![
2168            VerificationMethod::SasV1,
2169            VerificationMethod::QrCodeScanV1,
2170            VerificationMethod::QrCodeShowV1,
2171            VerificationMethod::ReciprocateV1,
2172        ]
2173    }
2174}