1use std::{collections::HashMap, sync::Arc};
16
17use matrix_sdk_common::locks::RwLock as StdRwLock;
18use ruma::{
19 DeviceId, EventId, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, RoomId,
20 SecondsSinceUnixEpoch, TransactionId, UInt, UserId,
21 events::{
22 AnyToDeviceEvent, AnyToDeviceEventContent, ToDeviceEvent,
23 key::verification::VerificationMethod,
24 },
25 serde::Raw,
26 uint,
27};
28use tokio::sync::Mutex;
29use tracing::{Span, debug, info, instrument, trace, warn};
30
31use super::{
32 FlowId, Verification, VerificationResult, VerificationStore,
33 cache::{RequestInfo, VerificationCache},
34 event_enums::{AnyEvent, AnyVerificationContent, OutgoingContent},
35 requests::VerificationRequest,
36 sas::Sas,
37};
38use crate::{
39 DeviceData, OtherUserIdentityData,
40 olm::{PrivateCrossSigningIdentity, StaticAccountData},
41 store::{CryptoStoreError, CryptoStoreWrapper},
42 types::requests::{
43 OutgoingRequest, OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest,
44 },
45};
46
47#[derive(Clone, Debug)]
48pub struct VerificationMachine {
49 pub(crate) store: VerificationStore,
50 verifications: VerificationCache,
51 requests: Arc<StdRwLock<HashMap<OwnedUserId, HashMap<String, VerificationRequest>>>>,
52}
53
54impl VerificationMachine {
55 pub(crate) fn new(
56 account: StaticAccountData,
57 identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
58 store: Arc<CryptoStoreWrapper>,
59 ) -> Self {
60 Self {
61 store: VerificationStore { account, private_identity: identity, inner: store },
62 verifications: VerificationCache::new(),
63 requests: Default::default(),
64 }
65 }
66
67 pub(crate) fn own_user_id(&self) -> &UserId {
68 &self.store.account.user_id
69 }
70
71 pub(crate) fn own_device_id(&self) -> &DeviceId {
72 &self.store.account.device_id
73 }
74
75 pub(crate) fn request_to_device_verification(
76 &self,
77 user_id: &UserId,
78 recipient_devices: Vec<OwnedDeviceId>,
79 methods: Option<Vec<VerificationMethod>>,
80 ) -> (VerificationRequest, OutgoingVerificationRequest) {
81 let flow_id = FlowId::from(TransactionId::new());
82
83 let verification = VerificationRequest::new(
84 self.verifications.clone(),
85 self.store.clone(),
86 flow_id,
87 user_id,
88 recipient_devices,
89 methods,
90 );
91
92 self.insert_request(verification.clone());
93
94 let request = verification.request_to_device();
95
96 (verification, request.into())
97 }
98
99 pub fn request_verification(
100 &self,
101 identity: &OtherUserIdentityData,
102 room_id: &RoomId,
103 request_event_id: &EventId,
104 methods: Option<Vec<VerificationMethod>>,
105 ) -> VerificationRequest {
106 let flow_id = FlowId::InRoom(room_id.to_owned(), request_event_id.to_owned());
107
108 let request = VerificationRequest::new(
109 self.verifications.clone(),
110 self.store.clone(),
111 flow_id,
112 identity.user_id(),
113 vec![],
114 methods,
115 );
116
117 self.insert_request(request.clone());
118
119 request
120 }
121
122 pub async fn start_sas(
123 &self,
124 device: DeviceData,
125 ) -> Result<(Sas, OutgoingVerificationRequest), CryptoStoreError> {
126 let identities = self.store.get_identities(device.clone()).await?;
127 let (sas, content) = Sas::start(identities, TransactionId::new(), true, None, None);
128
129 let request = match content {
130 OutgoingContent::Room(r, c) => {
131 RoomMessageRequest { room_id: r, txn_id: TransactionId::new(), content: c }.into()
132 }
133 OutgoingContent::ToDevice(c) => {
134 let request = ToDeviceRequest::with_id(
135 device.user_id(),
136 device.device_id().to_owned(),
137 &c,
138 TransactionId::new(),
139 );
140
141 self.verifications.insert_sas(sas.clone());
142
143 request.into()
144 }
145 };
146
147 Ok((sas, request))
148 }
149
150 pub fn get_request(
151 &self,
152 user_id: &UserId,
153 flow_id: impl AsRef<str>,
154 ) -> Option<VerificationRequest> {
155 self.requests.read().get(user_id)?.get(flow_id.as_ref()).cloned()
156 }
157
158 pub fn get_requests(&self, user_id: &UserId) -> Vec<VerificationRequest> {
159 self.requests.read().get(user_id).map(|v| v.values().cloned().collect()).unwrap_or_default()
160 }
161
162 fn insert_request(&self, request: VerificationRequest) {
166 if let Some(r) = self.get_request(request.other_user(), request.flow_id().as_str()) {
167 debug!(flow_id = r.flow_id().as_str(), "Ignoring known verification request",);
168 return;
169 }
170
171 let mut requests = self.requests.write();
172 let user_requests = requests.entry(request.other_user().to_owned()).or_default();
173
174 for old_verification in user_requests.values_mut() {
178 if !old_verification.is_cancelled() {
179 warn!(
180 "Received a new verification request whilst another request \
181 with the same user is ongoing. Cancelling both requests."
182 );
183
184 if let Some(r) = old_verification.cancel() {
185 self.verifications.add_request(r.into())
186 }
187
188 if let Some(r) = request.cancel() {
189 self.verifications.add_request(r.into())
190 }
191 }
192 }
193
194 user_requests.insert(request.flow_id().as_str().to_owned(), request);
198 }
199
200 pub fn get_verification(&self, user_id: &UserId, flow_id: &str) -> Option<Verification> {
201 self.verifications.get(user_id, flow_id)
202 }
203
204 pub fn get_sas(&self, user_id: &UserId, flow_id: &str) -> Option<Box<Sas>> {
205 self.verifications.get_sas(user_id, flow_id)
206 }
207
208 fn is_timestamp_valid(timestamp: MilliSecondsSinceUnixEpoch) -> bool {
209 let old_timestamp_threshold: UInt = uint!(600);
211 let timestamp_threshold: UInt = uint!(300);
214
215 let timestamp = timestamp.as_secs();
216 let now = SecondsSinceUnixEpoch::now().get();
217
218 !(now.saturating_sub(timestamp) > old_timestamp_threshold
219 || timestamp.saturating_sub(now) > timestamp_threshold)
220 }
221
222 fn queue_up_content(
223 &self,
224 recipient: &UserId,
225 recipient_device: &DeviceId,
226 content: OutgoingContent,
227 request_id: Option<RequestInfo>,
228 ) {
229 self.verifications.queue_up_content(recipient, recipient_device, content, request_id)
230 }
231
232 pub fn mark_request_as_sent(&self, request_id: &TransactionId) {
233 self.verifications.mark_request_as_sent(request_id);
234 }
235
236 pub fn outgoing_messages(&self) -> Vec<OutgoingRequest> {
237 self.verifications.outgoing_requests()
238 }
239
240 pub fn garbage_collect(&self) -> Vec<Raw<AnyToDeviceEvent>> {
241 let mut events = vec![];
242
243 let mut requests: Vec<OutgoingVerificationRequest> = {
244 let mut requests = self.requests.write();
245
246 for user_verification in requests.values_mut() {
247 user_verification.retain(|_, v| !(v.is_done() || v.is_cancelled()));
248 }
249 requests.retain(|_, v| !v.is_empty());
250
251 requests.values().flatten().filter_map(|(_, v)| v.cancel_if_timed_out()).collect()
252 };
253
254 requests.extend(self.verifications.garbage_collect());
255
256 for request in requests {
257 if let Ok(OutgoingContent::ToDevice(to_device)) = request.clone().try_into()
258 && let AnyToDeviceEventContent::KeyVerificationCancel(content) = *to_device
259 {
260 let event = ToDeviceEvent::new(self.own_user_id().to_owned(), content);
261
262 events.push(
263 Raw::new(&event)
264 .expect("Failed to serialize m.key_verification.cancel event")
265 .cast(),
266 );
267 }
268
269 self.verifications.add_verification_request(request)
270 }
271
272 events
273 }
274
275 async fn mark_sas_as_done(
276 &self,
277 sas: &Sas,
278 out_content: Option<OutgoingContent>,
279 ) -> Result<(), CryptoStoreError> {
280 match sas.mark_as_done().await? {
281 VerificationResult::Ok => {
282 if let Some(c) = out_content {
283 self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c, None);
284 }
285 }
286 VerificationResult::Cancel(c) => {
287 if let Some(r) = sas.cancel_with_code(c) {
288 self.verifications.add_request(r.into());
289 }
290 }
291 VerificationResult::SignatureUpload(r) => {
292 self.verifications.add_request(r.into());
293
294 if let Some(c) = out_content {
295 self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c, None);
296 }
297 }
298 }
299
300 Ok(())
301 }
302
303 #[instrument(skip_all, fields(flow_id))]
304 pub async fn receive_any_event(
305 &self,
306 event: impl Into<AnyEvent<'_>>,
307 ) -> Result<(), CryptoStoreError> {
308 let event = event.into();
309
310 let Ok(flow_id) = FlowId::try_from(&event) else {
311 return Ok(());
313 };
314 Span::current().record("flow_id", flow_id.as_str());
315
316 let flow_id_mismatch = || {
317 warn!(
318 flow_id = flow_id.as_str(),
319 "Received a verification event with a mismatched flow id, \
320 the verification object was created for a in-room \
321 verification but an event was received over to-device \
322 messaging or vice versa"
323 );
324 };
325
326 let event_sent_from_us = |event: &AnyEvent<'_>, from_device: &DeviceId| {
327 if event.sender() == self.store.account.user_id {
328 from_device == self.store.account.device_id || event.is_room_event()
329 } else {
330 false
331 }
332 };
333
334 let Some(content) = event.verification_content() else { return Ok(()) };
335 match &content {
336 AnyVerificationContent::Request(r) => {
337 info!(
338 sender = ?event.sender(),
339 from_device = r.from_device().as_str(),
340 "Received a new verification request",
341 );
342
343 let Some(timestamp) = event.timestamp() else {
344 warn!(
345 from_device = r.from_device().as_str(),
346 "The key verification request didn't contain a valid timestamp"
347 );
348 return Ok(());
349 };
350
351 if !Self::is_timestamp_valid(timestamp) {
352 info!(
353 from_device = r.from_device().as_str(),
354 ?timestamp,
355 "The received verification request was too old or too far into the future",
356 );
357 return Ok(());
358 }
359
360 if event_sent_from_us(&event, r.from_device()) {
361 trace!(
362 from_device = r.from_device().as_str(),
363 "The received verification request was sent by us, ignoring it",
364 );
365 return Ok(());
366 }
367
368 let Some(device_data) =
369 self.store.get_device(event.sender(), r.from_device()).await?
370 else {
371 warn!(
372 "Could not retrieve the device data for the incoming verification request, \
373 ignoring it"
374 );
375 return Ok(());
376 };
377
378 let request = VerificationRequest::from_request(
379 self.verifications.clone(),
380 self.store.clone(),
381 event.sender(),
382 flow_id,
383 r,
384 device_data,
385 );
386
387 self.insert_request(request);
388 }
389 AnyVerificationContent::Cancel(c) => {
390 if let Some(verification) = self.get_request(event.sender(), flow_id.as_str()) {
391 verification.receive_cancel(event.sender(), c);
392 }
393
394 if let Some(verification) = self.get_verification(event.sender(), flow_id.as_str())
395 {
396 match verification {
397 Verification::SasV1(sas) => {
398 let _ = sas.receive_any_event(event.sender(), &content);
400 }
401 #[cfg(feature = "qrcode")]
402 Verification::QrV1(qr) => qr.receive_cancel(event.sender(), c),
403 }
404 }
405 }
406 AnyVerificationContent::Ready(c) => {
407 let Some(request) = self.get_request(event.sender(), flow_id.as_str()) else {
408 return Ok(());
409 };
410
411 if request.flow_id() == &flow_id {
412 if let Some(device_data) =
413 self.store.get_device(event.sender(), c.from_device()).await?
414 {
415 request.receive_ready(event.sender(), c, device_data);
416 } else {
417 warn!("Could not retrieve the data for the accepting device, ignoring it");
418 }
419 } else {
420 flow_id_mismatch();
421 }
422 }
423 AnyVerificationContent::Start(c) => {
424 if let Some(request) = self.get_request(event.sender(), flow_id.as_str()) {
425 if request.flow_id() == &flow_id {
426 Box::pin(request.receive_start(event.sender(), c)).await?
427 } else {
428 flow_id_mismatch();
429 }
430 } else if let FlowId::ToDevice(_) = flow_id {
431 if let Some(device) =
434 self.store.get_device(event.sender(), c.from_device()).await?
435 {
436 let identities = self.store.get_identities(device).await?;
437
438 match Sas::from_start_event(flow_id, c, identities, None, false) {
439 Ok(sas) => {
440 self.verifications.insert_sas(sas);
441 }
442 Err(cancellation) => self.queue_up_content(
443 event.sender(),
444 c.from_device(),
445 cancellation,
446 None,
447 ),
448 }
449 }
450 }
451 }
452 AnyVerificationContent::Accept(_) | AnyVerificationContent::Key(_) => {
453 let Some(sas) = self.get_sas(event.sender(), flow_id.as_str()) else {
454 return Ok(());
455 };
456
457 if sas.flow_id() != &flow_id {
458 flow_id_mismatch();
459 return Ok(());
460 }
461
462 let Some((content, request_info)) = sas.receive_any_event(event.sender(), &content)
463 else {
464 return Ok(());
465 };
466
467 self.queue_up_content(
468 sas.other_user_id(),
469 sas.other_device_id(),
470 content,
471 request_info,
472 );
473 }
474 AnyVerificationContent::Mac(_) => {
475 let Some(s) = self.get_sas(event.sender(), flow_id.as_str()) else { return Ok(()) };
476
477 if s.flow_id() != &flow_id {
478 flow_id_mismatch();
479 return Ok(());
480 }
481
482 let content = s.receive_any_event(event.sender(), &content);
483
484 if s.is_done() {
485 Box::pin(self.mark_sas_as_done(&s, content.map(|(c, _)| c))).await?;
486 } else {
487 let Some((content, request_id)) = content else { return Ok(()) };
492
493 self.queue_up_content(
494 s.other_user_id(),
495 s.other_device_id(),
496 content,
497 request_id,
498 );
499 }
500 }
501 AnyVerificationContent::Done(c) => {
502 if let Some(verification) = self.get_request(event.sender(), flow_id.as_str()) {
503 verification.receive_done(event.sender(), c);
504 }
505
506 #[allow(clippy::single_match)]
507 match self.get_verification(event.sender(), flow_id.as_str()) {
508 Some(Verification::SasV1(sas)) => {
509 let content = sas.receive_any_event(event.sender(), &content);
510
511 if sas.is_done() {
512 Box::pin(self.mark_sas_as_done(&sas, content.map(|(c, _)| c))).await?;
513 }
514 }
515 #[cfg(feature = "qrcode")]
516 Some(Verification::QrV1(qr)) => {
517 let (cancellation, request) = Box::pin(qr.receive_done(c)).await?;
518
519 if let Some(c) = cancellation {
520 self.verifications.add_request(c.into())
521 }
522
523 if let Some(s) = request {
524 self.verifications.add_request(s.into())
525 }
526 }
527 None => {}
528 }
529 }
530 }
531
532 Ok(())
533 }
534
535 #[cfg(test)]
541 pub async fn get_own_user_identity_data(
542 &self,
543 ) -> Result<crate::OwnUserIdentityData, crate::SignatureError> {
544 self.store.private_identity.lock().await.to_public_identity().await
545 }
546}
547
548#[cfg(test)]
549mod tests {
550 use std::sync::Arc;
551
552 use matrix_sdk_test::async_test;
553 use ruma::TransactionId;
554 use tokio::sync::Mutex;
555
556 use super::{Sas, VerificationMachine};
557 use crate::{
558 Account, VerificationRequest,
559 olm::PrivateCrossSigningIdentity,
560 store::{CryptoStoreWrapper, MemoryStore},
561 verification::{
562 FlowId, VerificationStore,
563 cache::VerificationCache,
564 event_enums::{AcceptContent, KeyContent, MacContent, OutgoingContent},
565 tests::{alice_device_id, alice_id, setup_stores, wrap_any_to_device_content},
566 },
567 };
568
569 async fn verification_machine() -> (VerificationMachine, VerificationStore) {
570 let (_account, store, _bob, bob_store) = setup_stores().await;
571
572 let machine = VerificationMachine {
573 store,
574 verifications: VerificationCache::new(),
575 requests: Default::default(),
576 };
577
578 (machine, bob_store)
579 }
580
581 async fn setup_verification_machine() -> (VerificationMachine, Sas) {
582 let (machine, bob_store) = verification_machine().await;
583
584 let alice_device =
585 bob_store.get_device(alice_id(), alice_device_id()).await.unwrap().unwrap();
586
587 let identities = bob_store.get_identities(alice_device).await.unwrap();
588 let (bob_sas, start_content) =
589 Sas::start(identities, TransactionId::new(), true, None, None);
590
591 machine
592 .receive_any_event(&wrap_any_to_device_content(bob_sas.user_id(), start_content))
593 .await
594 .unwrap();
595
596 (machine, bob_sas)
597 }
598
599 #[async_test]
600 async fn test_create() {
601 let alice = Account::with_device_id(alice_id(), alice_device_id());
602 let identity = Arc::new(Mutex::new(PrivateCrossSigningIdentity::empty(alice_id())));
603 let _ = VerificationMachine::new(
604 alice.static_data,
605 identity,
606 Arc::new(CryptoStoreWrapper::new(alice_id(), alice_device_id(), MemoryStore::new())),
607 );
608 }
609
610 #[async_test]
611 async fn test_full_flow() {
612 let (alice_machine, bob) = setup_verification_machine().await;
613
614 let alice = alice_machine.get_sas(bob.user_id(), bob.flow_id().as_str()).unwrap();
615
616 let request = alice.accept().unwrap();
617
618 let content = OutgoingContent::try_from(request).unwrap();
619 let content = AcceptContent::try_from(&content).unwrap().into();
620
621 let (content, request_info) = bob.receive_any_event(alice.user_id(), &content).unwrap();
622
623 let event = wrap_any_to_device_content(bob.user_id(), content);
624
625 assert!(alice_machine.verifications.outgoing_requests().is_empty());
626 alice_machine.receive_any_event(&event).await.unwrap();
627 assert!(!alice_machine.verifications.outgoing_requests().is_empty());
628
629 let request = alice_machine.verifications.outgoing_requests().first().cloned().unwrap();
630 let txn_id = request.request_id().to_owned();
631 let content = OutgoingContent::try_from(request).unwrap();
632 let content = KeyContent::try_from(&content).unwrap().into();
633
634 alice_machine.mark_request_as_sent(&txn_id);
635
636 assert!(bob.receive_any_event(alice.user_id(), &content).is_none());
637
638 assert!(alice.emoji().is_some());
639 assert!(bob.emoji().is_none());
642 bob.mark_request_as_sent(&request_info.unwrap().request_id);
643 assert!(bob.emoji().is_some());
644 assert_eq!(alice.emoji(), bob.emoji());
645
646 let mut requests = alice.confirm().await.unwrap().0;
647 assert!(requests.len() == 1);
648 let request = requests.pop().unwrap();
649 let content = OutgoingContent::try_from(request).unwrap();
650 let content = MacContent::try_from(&content).unwrap().into();
651 bob.receive_any_event(alice.user_id(), &content);
652
653 let mut requests = bob.confirm().await.unwrap().0;
654 assert!(requests.len() == 1);
655 let request = requests.pop().unwrap();
656 let content = OutgoingContent::try_from(request).unwrap();
657 let content = MacContent::try_from(&content).unwrap().into();
658 alice.receive_any_event(bob.user_id(), &content);
659
660 assert!(alice.is_done());
661 assert!(bob.is_done());
662 }
663
664 #[cfg(not(target_os = "macos"))]
665 #[allow(unknown_lints, clippy::unchecked_duration_subtraction)]
666 #[async_test]
667 async fn test_timing_out() {
668 use std::time::Duration;
669
670 use ruma::time::Instant;
671
672 let (alice_machine, bob) = setup_verification_machine().await;
673 let alice = alice_machine.get_sas(bob.user_id(), bob.flow_id().as_str()).unwrap();
674
675 assert!(!alice.timed_out());
676 assert!(alice_machine.verifications.outgoing_requests().is_empty());
677
678 alice.set_creation_time(Instant::now() - Duration::from_secs(60 * 15));
680 assert!(alice.timed_out());
681 assert!(alice_machine.verifications.outgoing_requests().is_empty());
682 alice_machine.garbage_collect();
683 assert!(!alice_machine.verifications.outgoing_requests().is_empty());
684 alice_machine.garbage_collect();
685 assert!(alice_machine.verifications.is_empty());
686 }
687
688 #[async_test]
691 async fn test_double_verification_cancellation() {
692 let (machine, bob_store) = verification_machine().await;
693
694 let alice_device =
695 bob_store.get_device(alice_id(), alice_device_id()).await.unwrap().unwrap();
696 let identities = bob_store.get_identities(alice_device).await.unwrap();
697
698 let (bob_sas, start_content) =
700 Sas::start(identities.clone(), TransactionId::new(), true, None, None);
701
702 machine
703 .receive_any_event(&wrap_any_to_device_content(bob_sas.user_id(), start_content))
704 .await
705 .unwrap();
706
707 let alice_sas = machine.get_sas(bob_sas.user_id(), bob_sas.flow_id().as_str()).unwrap();
708
709 assert!(!alice_sas.is_cancelled());
711
712 let second_transaction_id = TransactionId::new();
713 let (bob_sas, start_content) =
714 Sas::start(identities, second_transaction_id.clone(), true, None, None);
715 machine
716 .receive_any_event(&wrap_any_to_device_content(bob_sas.user_id(), start_content))
717 .await
718 .unwrap();
719
720 let second_sas = machine.get_sas(bob_sas.user_id(), bob_sas.flow_id().as_str()).unwrap();
721
722 assert_eq!(second_sas.flow_id().as_str(), second_transaction_id);
724
725 assert!(alice_sas.is_cancelled());
727 assert!(second_sas.is_cancelled());
728 }
729
730 #[async_test]
733 async fn test_double_verification_request_cancellation() {
734 let (machine, bob_store) = verification_machine().await;
735
736 let flow_id = FlowId::ToDevice("TEST_FLOW_ID".into());
738
739 let bob_request = VerificationRequest::new(
740 VerificationCache::new(),
741 bob_store.clone(),
742 flow_id.clone(),
743 alice_id(),
744 vec![],
745 None,
746 );
747
748 let request = bob_request.request_to_device();
749 let content: OutgoingContent = request.try_into().unwrap();
750
751 machine
752 .receive_any_event(&wrap_any_to_device_content(bob_request.own_user_id(), content))
753 .await
754 .unwrap();
755
756 let alice_request =
757 machine.get_request(bob_request.own_user_id(), bob_request.flow_id().as_str()).unwrap();
758
759 assert!(!alice_request.is_cancelled());
761
762 let second_transaction_id = TransactionId::new();
763 let bob_request = VerificationRequest::new(
764 VerificationCache::new(),
765 bob_store,
766 second_transaction_id.clone().into(),
767 alice_id(),
768 vec![],
769 None,
770 );
771
772 let request = bob_request.request_to_device();
773 let content: OutgoingContent = request.try_into().unwrap();
774
775 machine
776 .receive_any_event(&wrap_any_to_device_content(bob_request.own_user_id(), content))
777 .await
778 .unwrap();
779
780 let second_request =
781 machine.get_request(bob_request.own_user_id(), bob_request.flow_id().as_str()).unwrap();
782
783 assert_eq!(second_request.flow_id().as_str(), second_transaction_id);
785
786 assert!(alice_request.is_cancelled());
788 assert!(second_request.is_cancelled());
789 }
790
791 #[async_test]
795 async fn test_ignore_identical_verification_request() {
796 let (machine, bob_store) = verification_machine().await;
797
798 let flow_id = FlowId::ToDevice("TEST_FLOW_ID".into());
800
801 let bob_request = VerificationRequest::new(
802 VerificationCache::new(),
803 bob_store.clone(),
804 flow_id.clone(),
805 alice_id(),
806 vec![],
807 None,
808 );
809
810 let request = bob_request.request_to_device();
811 let content: OutgoingContent = request.try_into().unwrap();
812
813 machine
814 .receive_any_event(&wrap_any_to_device_content(bob_request.own_user_id(), content))
815 .await
816 .unwrap();
817
818 let first_request =
819 machine.get_request(bob_request.own_user_id(), bob_request.flow_id().as_str()).unwrap();
820
821 assert!(!first_request.is_cancelled());
823
824 let bob_request = VerificationRequest::new(
826 VerificationCache::new(),
827 bob_store,
828 flow_id.clone(),
829 alice_id(),
830 vec![],
831 None,
832 );
833
834 let request = bob_request.request_to_device();
835 let content: OutgoingContent = request.try_into().unwrap();
836
837 machine
838 .receive_any_event(&wrap_any_to_device_content(bob_request.own_user_id(), content))
839 .await
840 .unwrap();
841
842 let second_request =
843 machine.get_request(bob_request.own_user_id(), bob_request.flow_id().as_str()).unwrap();
844
845 assert!(!first_request.is_cancelled());
847 assert!(!second_request.is_cancelled());
848 }
849}