1mod cache;
16mod event_enums;
17mod machine;
18#[cfg(feature = "qrcode")]
19mod qrcode;
20mod requests;
21mod sas;
22
23use std::{collections::HashMap, ops::Deref, sync::Arc};
24
25use as_variant::as_variant;
26use event_enums::OutgoingContent;
27pub use machine::VerificationMachine;
28#[cfg(feature = "qrcode")]
29pub use qrcode::{QrVerification, QrVerificationState, ScanError};
30pub use requests::{VerificationRequest, VerificationRequestState};
31#[cfg(feature = "qrcode")]
32use ruma::events::key::verification::done::{
33 KeyVerificationDoneEventContent, ToDeviceKeyVerificationDoneEventContent,
34};
35use ruma::{
36 DeviceId, EventId, OwnedDeviceId, OwnedEventId, OwnedRoomId, OwnedTransactionId, RoomId,
37 UserId,
38 api::client::keys::upload_signatures::v3::Request as SignatureUploadRequest,
39 events::{
40 AnyMessageLikeEventContent, AnyToDeviceEventContent,
41 key::verification::cancel::{
42 CancelCode, KeyVerificationCancelEventContent,
43 ToDeviceKeyVerificationCancelEventContent,
44 },
45 relation::Reference,
46 },
47};
48pub use sas::{AcceptSettings, AcceptedProtocols, EmojiShortAuthString, Sas, SasState};
49use tokio::sync::Mutex;
50use tracing::{debug, error, info, warn};
51
52use crate::{
53 CryptoStoreError, DeviceData, LocalTrust, OwnUserIdentityData, UserIdentityData,
54 error::SignatureError,
55 gossiping::{GossipMachine, GossipRequest},
56 olm::{PrivateCrossSigningIdentity, StaticAccountData},
57 store::{CryptoStoreWrapper, types::Changes},
58 types::{Signatures, requests::OutgoingVerificationRequest},
59};
60
61#[derive(Clone, Debug)]
62pub(crate) struct VerificationStore {
63 pub account: StaticAccountData,
64 pub private_identity: Arc<Mutex<PrivateCrossSigningIdentity>>,
65 inner: Arc<CryptoStoreWrapper>,
66}
67
68#[derive(Debug, Clone, PartialEq, Eq, PartialOrd)]
76pub struct Emoji {
77 pub symbol: &'static str,
80 pub description: &'static str,
82}
83
84pub fn format_emojis(emojis: [Emoji; 7]) -> String {
89 let (emojis, descriptions): (Vec<_>, Vec<_>) =
90 emojis.iter().map(|e| (e.symbol, e.description)).unzip();
91
92 let center_emoji = |emoji: &str| -> String {
93 const EMOJI_WIDTH: usize = 2;
94 const VARIATION_SELECTOR_EMOJIS: [&str; 7] = ["☁️", "❤️", "☂️", "✏️", "✂️", "☎️", "✈️"];
99
100 let emoji = if VARIATION_SELECTOR_EMOJIS.contains(&emoji) {
103 format!("{emoji} ")
104 } else {
105 emoji.to_owned()
106 };
107
108 let placeholder = ".".repeat(EMOJI_WIDTH);
111
112 format!("{placeholder:^12}").replace(&placeholder, &emoji)
113 };
114
115 let emoji_string = emojis.iter().map(|e| center_emoji(e)).collect::<Vec<_>>().join("");
116
117 let description = descriptions.iter().map(|d| format!("{d:^12}")).collect::<Vec<_>>().join("");
118
119 format!("{emoji_string}\n{description}")
120}
121
122impl VerificationStore {
123 pub async fn get_device(
124 &self,
125 user_id: &UserId,
126 device_id: &DeviceId,
127 ) -> Result<Option<DeviceData>, CryptoStoreError> {
128 Ok(self.inner.get_device(user_id, device_id).await?.filter(|d| {
129 !(d.user_id() == self.account.user_id && d.device_id() == self.account.device_id)
130 }))
131 }
132
133 pub async fn get_user_identity(
134 &self,
135 user_id: &UserId,
136 ) -> Result<Option<UserIdentityData>, CryptoStoreError> {
137 self.inner.get_user_identity(user_id).await
138 }
139
140 pub async fn get_identities(
141 &self,
142 device_being_verified: DeviceData,
143 ) -> Result<IdentitiesBeingVerified, CryptoStoreError> {
144 let identity_being_verified =
145 self.get_user_identity(device_being_verified.user_id()).await?;
146
147 Ok(IdentitiesBeingVerified {
148 private_identity: self.private_identity.lock().await.clone(),
149 store: self.clone(),
150 device_being_verified,
151 own_identity: self
152 .get_user_identity(&self.account.user_id)
153 .await?
154 .and_then(|i| i.into_own()),
155 identity_being_verified,
156 })
157 }
158
159 pub async fn save_changes(&self, changes: Changes) -> Result<(), CryptoStoreError> {
160 self.inner.save_changes(changes).await
161 }
162
163 pub async fn get_user_devices(
164 &self,
165 user_id: &UserId,
166 ) -> Result<HashMap<OwnedDeviceId, DeviceData>, CryptoStoreError> {
167 self.inner.get_user_devices(user_id).await
168 }
169
170 pub async fn device_signatures(&self) -> Result<Option<Signatures>, CryptoStoreError> {
172 Ok(self
173 .inner
174 .get_device(&self.account.user_id, &self.account.device_id)
175 .await?
176 .map(|d| d.signatures().to_owned()))
177 }
178
179 pub fn inner(&self) -> &CryptoStoreWrapper {
180 self.inner.deref()
181 }
182}
183
184#[derive(Clone, Debug)]
186#[non_exhaustive]
187pub enum Verification {
188 SasV1(Box<Sas>),
191 #[cfg(feature = "qrcode")]
194 QrV1(Box<QrVerification>),
195}
196
197impl Verification {
198 pub fn sas_v1(self) -> Option<Box<Sas>> {
200 as_variant!(self, Verification::SasV1)
201 }
202
203 #[cfg(feature = "qrcode")]
205 pub fn qr_v1(self) -> Option<Box<QrVerification>> {
206 as_variant!(self, Verification::QrV1)
207 }
208
209 pub fn is_done(&self) -> bool {
211 match self {
212 Verification::SasV1(s) => s.is_done(),
213 #[cfg(feature = "qrcode")]
214 Verification::QrV1(qr) => qr.is_done(),
215 }
216 }
217
218 pub fn flow_id(&self) -> &str {
220 match self {
221 Verification::SasV1(s) => s.flow_id().as_str(),
222 #[cfg(feature = "qrcode")]
223 Verification::QrV1(qr) => qr.flow_id().as_str(),
224 }
225 }
226
227 pub fn is_cancelled(&self) -> bool {
229 match self {
230 Verification::SasV1(s) => s.is_cancelled(),
231 #[cfg(feature = "qrcode")]
232 Verification::QrV1(qr) => qr.is_cancelled(),
233 }
234 }
235
236 pub fn user_id(&self) -> &UserId {
238 match self {
239 Verification::SasV1(v) => v.user_id(),
240 #[cfg(feature = "qrcode")]
241 Verification::QrV1(v) => v.user_id(),
242 }
243 }
244
245 pub fn other_user(&self) -> &UserId {
247 match self {
248 Verification::SasV1(s) => s.other_user_id(),
249 #[cfg(feature = "qrcode")]
250 Verification::QrV1(qr) => qr.other_user_id(),
251 }
252 }
253
254 pub fn is_self_verification(&self) -> bool {
256 match self {
257 Verification::SasV1(v) => v.is_self_verification(),
258 #[cfg(feature = "qrcode")]
259 Verification::QrV1(v) => v.is_self_verification(),
260 }
261 }
262
263 fn cancel(&self) -> Option<OutgoingVerificationRequest> {
264 match self {
265 Verification::SasV1(v) => v.cancel(),
266 #[cfg(feature = "qrcode")]
267 Verification::QrV1(v) => v.cancel(),
268 }
269 }
270}
271
272impl From<Sas> for Verification {
273 fn from(sas: Sas) -> Self {
274 Self::SasV1(Box::new(sas))
275 }
276}
277
278#[cfg(feature = "qrcode")]
279impl From<QrVerification> for Verification {
280 fn from(qr: QrVerification) -> Self {
281 Self::QrV1(Box::new(qr))
282 }
283}
284
285#[cfg(feature = "qrcode")]
291#[derive(Clone, Debug)]
292pub struct Done {
293 verified_devices: Arc<[DeviceData]>,
294 verified_master_keys: Arc<[UserIdentityData]>,
295}
296
297#[cfg(feature = "qrcode")]
298impl Done {
299 pub fn as_content(&self, flow_id: &FlowId) -> OutgoingContent {
300 match flow_id {
301 FlowId::ToDevice(t) => AnyToDeviceEventContent::KeyVerificationDone(
302 ToDeviceKeyVerificationDoneEventContent::new(t.to_owned()),
303 )
304 .into(),
305 FlowId::InRoom(r, e) => (
306 r.to_owned(),
307 AnyMessageLikeEventContent::KeyVerificationDone(
308 KeyVerificationDoneEventContent::new(Reference::new(e.to_owned())),
309 ),
310 )
311 .into(),
312 }
313 }
314}
315
316#[derive(Clone, Debug)]
319pub struct CancelInfo {
320 cancelled_by_us: bool,
321 cancel_code: CancelCode,
322 reason: &'static str,
323}
324
325impl CancelInfo {
326 pub fn reason(&self) -> &'static str {
328 self.reason
329 }
330
331 pub fn cancel_code(&self) -> &CancelCode {
333 &self.cancel_code
334 }
335
336 pub fn cancelled_by_us(&self) -> bool {
338 self.cancelled_by_us
339 }
340}
341
342impl From<Cancelled> for CancelInfo {
343 fn from(c: Cancelled) -> Self {
344 Self { cancelled_by_us: c.cancelled_by_us, cancel_code: c.cancel_code, reason: c.reason }
345 }
346}
347
348#[derive(Clone, Debug)]
349pub struct Cancelled {
350 cancelled_by_us: bool,
351 cancel_code: CancelCode,
352 reason: &'static str,
353}
354
355impl Cancelled {
356 fn new(cancelled_by_us: bool, code: CancelCode) -> Self {
357 let reason = match code {
358 CancelCode::Accepted => {
359 "A m.key.verification.request was accepted by a different device."
360 }
361 CancelCode::InvalidMessage => "The received message was invalid.",
362 CancelCode::KeyMismatch => "The expected key did not match the verified one",
363 CancelCode::MismatchedCommitment => "The hash commitment did not match.",
364 CancelCode::MismatchedSas => "The SAS did not match.",
365 CancelCode::Timeout => "The verification process timed out.",
366 CancelCode::UnexpectedMessage => "The device received an unexpected message.",
367 CancelCode::UnknownMethod => {
368 "The device does not know how to handle the requested method."
369 }
370 CancelCode::UnknownTransaction => {
371 "The device does not know about the given transaction ID."
372 }
373 CancelCode::User => "The user cancelled the verification.",
374 CancelCode::UserMismatch => "The expected user did not match the verified user",
375 _ => "Unknown cancel reason",
376 };
377
378 Self { cancelled_by_us, cancel_code: code, reason }
379 }
380
381 pub fn as_content(&self, flow_id: &FlowId) -> OutgoingContent {
382 match flow_id {
383 FlowId::ToDevice(s) => AnyToDeviceEventContent::KeyVerificationCancel(
384 ToDeviceKeyVerificationCancelEventContent::new(
385 s.clone(),
386 self.reason.to_owned(),
387 self.cancel_code.clone(),
388 ),
389 )
390 .into(),
391
392 FlowId::InRoom(r, e) => (
393 r.clone(),
394 AnyMessageLikeEventContent::KeyVerificationCancel(
395 KeyVerificationCancelEventContent::new(
396 self.reason.to_owned(),
397 self.cancel_code.clone(),
398 Reference::new(e.clone()),
399 ),
400 ),
401 )
402 .into(),
403 }
404 }
405}
406
407#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd)]
410pub enum FlowId {
411 ToDevice(OwnedTransactionId),
413
414 InRoom(OwnedRoomId, OwnedEventId),
416}
417
418impl FlowId {
419 pub fn room_id(&self) -> Option<&RoomId> {
421 as_variant!(self, Self::InRoom(room_id, _) => room_id)
422 }
423
424 pub fn as_str(&self) -> &str {
426 match self {
427 Self::InRoom(_, event_id) => event_id.as_str(),
428 Self::ToDevice(transaction_id) => transaction_id.as_str(),
429 }
430 }
431}
432
433impl From<OwnedTransactionId> for FlowId {
434 fn from(transaction_id: OwnedTransactionId) -> Self {
435 Self::ToDevice(transaction_id)
436 }
437}
438
439impl From<(OwnedRoomId, OwnedEventId)> for FlowId {
440 fn from(ids: (OwnedRoomId, OwnedEventId)) -> Self {
441 Self::InRoom(ids.0, ids.1)
442 }
443}
444
445impl From<(&RoomId, &EventId)> for FlowId {
446 fn from(ids: (&RoomId, &EventId)) -> Self {
447 Self::InRoom(ids.0.to_owned(), ids.1.to_owned())
448 }
449}
450
451#[derive(Clone, Debug)]
453pub enum VerificationResult {
454 Ok,
456 Cancel(CancelCode),
458 SignatureUpload(SignatureUploadRequest),
460}
461
462#[derive(Clone, Debug)]
463pub struct IdentitiesBeingVerified {
464 private_identity: PrivateCrossSigningIdentity,
465 store: VerificationStore,
466 device_being_verified: DeviceData,
467 own_identity: Option<OwnUserIdentityData>,
468 identity_being_verified: Option<UserIdentityData>,
469}
470
471impl IdentitiesBeingVerified {
472 #[cfg(feature = "qrcode")]
473 async fn can_sign_devices(&self) -> bool {
474 self.private_identity.can_sign_devices().await
475 }
476
477 fn user_id(&self) -> &UserId {
478 self.private_identity.user_id()
479 }
480
481 fn is_self_verification(&self) -> bool {
482 self.user_id() == self.other_user_id()
483 }
484
485 fn other_user_id(&self) -> &UserId {
486 self.device_being_verified.user_id()
487 }
488
489 fn other_device_id(&self) -> &DeviceId {
490 self.device_being_verified.device_id()
491 }
492
493 fn other_device(&self) -> &DeviceData {
494 &self.device_being_verified
495 }
496
497 pub async fn mark_as_done(
498 &self,
499 verified_devices: Option<&[DeviceData]>,
500 verified_identities: Option<&[UserIdentityData]>,
501 ) -> Result<VerificationResult, CryptoStoreError> {
502 let device = self.mark_device_as_verified(verified_devices).await?;
503 let (identity, should_request_secrets) =
504 self.mark_identity_as_verified(verified_identities).await?;
505
506 if device.is_none() && identity.is_none() {
507 return Ok(VerificationResult::Cancel(CancelCode::KeyMismatch));
510 }
511
512 let mut changes = Changes::default();
513
514 let signature_request = if let Some(device) = device {
515 let signature_request = if device.user_id() == self.user_id() {
517 match self.private_identity.sign_device(&device).await {
518 Ok(r) => Some(r),
519 Err(SignatureError::MissingSigningKey) => {
520 warn!(
521 "Can't sign the device keys for {} {}, \
522 no private device signing key found",
523 device.user_id(),
524 device.device_id(),
525 );
526
527 None
528 }
529 Err(e) => {
530 error!(
531 user_id = ?device.user_id(),
532 device_id = ?device.device_id(),
533 "Error signing device keys: {e:?}",
534 );
535 None
536 }
537 }
538 } else {
539 None
540 };
541
542 changes.devices.changed.push(device);
543 signature_request
544 } else {
545 None
546 };
547
548 let identity_signature_request = if let Some(i) = identity {
549 let request = if let Some(i) = i.other() {
551 match self.private_identity.sign_user(i).await {
553 Ok(r) => Some(r),
554 Err(SignatureError::MissingSigningKey) => {
555 warn!(
556 user_id = ?i.user_id(),
557 "Can't sign the public cross signing keys, \
558 no private user signing key found",
559 );
560 None
561 }
562 Err(e) => {
563 error!(
564 user_id = ?i.user_id(),
565 "Error signing the public cross signing keys: {e:?}",
566 );
567 None
568 }
569 }
570 } else {
571 None
572 };
573
574 changes.identities.changed.push(i);
575 request
576 } else {
577 None
578 };
579
580 let merged_request = if let Some(mut r) = signature_request {
586 if let Some(user_request) = identity_signature_request {
587 r.signed_keys.extend(user_request.signed_keys);
588 }
589
590 Some(r)
591 } else {
592 identity_signature_request
593 };
594
595 if should_request_secrets {
596 let secret_requests = self.request_missing_secrets().await?;
597 changes.key_requests = secret_requests;
598 }
599
600 self.store.save_changes(changes).await?;
602
603 Ok(merged_request
604 .map(VerificationResult::SignatureUpload)
605 .unwrap_or(VerificationResult::Ok))
606 }
607
608 async fn request_missing_secrets(&self) -> Result<Vec<GossipRequest>, CryptoStoreError> {
609 let mut secrets = self.private_identity.get_missing_secrets().await;
610
611 if self.store.inner.load_backup_keys().await?.decryption_key.is_none() {
612 secrets.push(ruma::events::secret::request::SecretName::RecoveryKey);
613 }
614
615 Ok(GossipMachine::request_missing_secrets(self.user_id(), secrets))
616 }
617
618 async fn mark_identity_as_verified(
619 &self,
620 verified_identities: Option<&[UserIdentityData]>,
621 ) -> Result<(Option<UserIdentityData>, bool), CryptoStoreError> {
622 if self.identity_being_verified.is_none() {
625 return Ok((None, false));
626 }
627
628 let identity = self.store.get_user_identity(self.other_user_id()).await?;
629
630 Ok(if let Some(identity) = identity {
631 if self
632 .identity_being_verified
633 .as_ref()
634 .is_some_and(|i| i.master_key() == identity.master_key())
635 {
636 if verified_identities.is_some_and(|i| {
637 i.iter().any(|verified| verified.user_id() == identity.user_id())
638 }) {
639 info!(
640 user_id = ?self.other_user_id(),
641 "The interactive verification process verified the identity of \
642 the remote user: marking as verified."
643 );
644
645 let should_request_secrets = if let UserIdentityData::Own(i) = &identity {
646 i.mark_as_verified();
647 true
648 } else {
649 false
650 };
651
652 (Some(identity), should_request_secrets)
653 } else {
654 debug!(
659 user_id = ?self.other_user_id(),
660 "The interactive verification process didn't verify \
661 the user identity of the user that participated in \
662 the interactive verification",
663 );
664
665 (None, false)
666 }
667 } else {
668 warn!(
669 user_id = ?self.other_user_id(),
670 "The master keys of the user have changed while an interactive \
671 verification was going on, not marking the identity as verified.",
672 );
673
674 (None, false)
675 }
676 } else {
677 info!(
678 user_id = ?self.other_user_id(),
679 "The identity of the user was deleted while an interactive \
680 verification was going on.",
681 );
682 (None, false)
683 })
684 }
685
686 async fn mark_device_as_verified(
687 &self,
688 verified_devices: Option<&[DeviceData]>,
689 ) -> Result<Option<DeviceData>, CryptoStoreError> {
690 let device = self.store.get_device(self.other_user_id(), self.other_device_id()).await?;
691
692 let Some(device) = device else {
693 let device = &self.device_being_verified;
694 info!(
695 user_id = ?device.user_id(),
696 device_id = ?device.device_id(),
697 "The device was deleted while an interactive verification was going on.",
698 );
699 return Ok(None);
700 };
701
702 if device.keys() != self.device_being_verified.keys() {
703 warn!(
704 user_id = ?device.user_id(),
705 device_id = ?device.device_id(),
706 "The device keys have changed while an interactive verification \
707 was going on, not marking the device as verified.",
708 );
709 return Ok(None);
710 }
711
712 if verified_devices.is_some_and(|v| v.contains(&device)) {
713 info!(
714 user_id = ?device.user_id(),
715 device_id = ?device.device_id(),
716 "The interactive verification process verified the remote device: marking as verified.",
717 );
718
719 device.set_trust_state(LocalTrust::Verified);
720
721 Ok(Some(device))
722 } else {
723 debug!(
729 user_id = ?device.user_id(),
730 device_id = ?device.device_id(),
731 "The interactive verification process didn't verify the remote device",
732 );
733
734 Ok(None)
735 }
736 }
737}
738
739#[cfg(test)]
740pub(crate) mod tests {
741 use std::sync::Arc;
742
743 use ruma::{
744 DeviceId, UserId, device_id,
745 events::{AnyToDeviceEventContent, ToDeviceEvent},
746 user_id,
747 };
748 use tokio::sync::Mutex;
749
750 use super::{VerificationStore, event_enums::OutgoingContent};
751 use crate::{
752 Account, DeviceData, OtherUserIdentityData, OwnUserIdentityData,
753 olm::PrivateCrossSigningIdentity,
754 store::{
755 CryptoStore, CryptoStoreWrapper, MemoryStore,
756 types::{Changes, IdentityChanges},
757 },
758 types::{
759 events::ToDeviceEvents,
760 requests::{AnyOutgoingRequest, OutgoingRequest, OutgoingVerificationRequest},
761 },
762 };
763
764 pub(crate) fn request_to_event(
765 sender: &UserId,
766 request: &OutgoingVerificationRequest,
767 ) -> ToDeviceEvents {
768 let content =
769 request.to_owned().try_into().expect("Can't fetch content out of the request");
770 wrap_any_to_device_content(sender, content)
771 }
772
773 pub(crate) fn outgoing_request_to_event(
774 sender: &UserId,
775 request: &OutgoingRequest,
776 ) -> ToDeviceEvents {
777 match request.request() {
778 AnyOutgoingRequest::ToDeviceRequest(r) => request_to_event(sender, &r.clone().into()),
779 _ => panic!("Unsupported outgoing request"),
780 }
781 }
782
783 pub(crate) fn wrap_any_to_device_content(
784 sender: &UserId,
785 content: OutgoingContent,
786 ) -> ToDeviceEvents {
787 let OutgoingContent::ToDevice(content) = content else { unreachable!() };
788 let sender = sender.to_owned();
789
790 match *content {
791 AnyToDeviceEventContent::KeyVerificationRequest(c) => {
792 ToDeviceEvents::KeyVerificationRequest(ToDeviceEvent::new(sender, c))
793 }
794 AnyToDeviceEventContent::KeyVerificationReady(c) => {
795 ToDeviceEvents::KeyVerificationReady(ToDeviceEvent::new(sender, c))
796 }
797 AnyToDeviceEventContent::KeyVerificationKey(c) => {
798 ToDeviceEvents::KeyVerificationKey(ToDeviceEvent::new(sender, c))
799 }
800 AnyToDeviceEventContent::KeyVerificationStart(c) => {
801 ToDeviceEvents::KeyVerificationStart(ToDeviceEvent::new(sender, c))
802 }
803 AnyToDeviceEventContent::KeyVerificationAccept(c) => {
804 ToDeviceEvents::KeyVerificationAccept(ToDeviceEvent::new(sender, c))
805 }
806 AnyToDeviceEventContent::KeyVerificationMac(c) => {
807 ToDeviceEvents::KeyVerificationMac(ToDeviceEvent::new(sender, c))
808 }
809 AnyToDeviceEventContent::KeyVerificationDone(c) => {
810 ToDeviceEvents::KeyVerificationDone(ToDeviceEvent::new(sender, c))
811 }
812
813 _ => unreachable!(),
814 }
815 }
816
817 pub fn alice_id() -> &'static UserId {
818 user_id!("@alice:example.org")
819 }
820
821 pub fn alice_device_id() -> &'static DeviceId {
822 device_id!("JLAFKJWSCS")
823 }
824
825 pub fn bob_id() -> &'static UserId {
826 user_id!("@bob:example.org")
827 }
828
829 pub fn bob_device_id() -> &'static DeviceId {
830 device_id!("BOBDEVICE")
831 }
832
833 pub(crate) async fn setup_stores() -> (Account, VerificationStore, Account, VerificationStore) {
834 let alice = Account::with_device_id(alice_id(), alice_device_id());
835 let alice_store = MemoryStore::new();
836 let alice_private_identity = PrivateCrossSigningIdentity::for_account(
837 &alice,
838 #[cfg(feature = "experimental-x509-identity-verification")]
839 None,
840 )
841 .await
842 .unwrap();
843 let alice_private_identity = Mutex::new(alice_private_identity);
844
845 let bob = Account::with_device_id(bob_id(), bob_device_id());
846 let bob_store = MemoryStore::new();
847 let bob_private_identity = PrivateCrossSigningIdentity::for_account(
848 &bob,
849 #[cfg(feature = "experimental-x509-identity-verification")]
850 None,
851 )
852 .await
853 .unwrap();
854 let bob_private_identity = Mutex::new(bob_private_identity);
855
856 let alice_public_identity =
857 OtherUserIdentityData::from_private(&*alice_private_identity.lock().await).await;
858 let alice_identity_data =
859 OwnUserIdentityData::from_private(&*alice_private_identity.lock().await).await;
860 let bob_public_identity =
861 OtherUserIdentityData::from_private(&*bob_private_identity.lock().await).await;
862 let bob_identity_data =
863 OwnUserIdentityData::from_private(&*bob_private_identity.lock().await).await;
864
865 let alice_device = DeviceData::from_account(&alice);
866 let bob_device = DeviceData::from_account(&bob);
867
868 let alice_changes = Changes {
869 identities: IdentityChanges {
870 new: vec![alice_identity_data.into(), bob_public_identity.into()],
871 changed: vec![],
872 unchanged: vec![],
873 },
874 ..Default::default()
875 };
876 alice_store.save_changes(alice_changes).await.unwrap();
877 alice_store.save_devices(vec![bob_device]);
878
879 let bob_changes = Changes {
880 identities: IdentityChanges {
881 new: vec![bob_identity_data.into(), alice_public_identity.into()],
882 changed: vec![],
883 unchanged: vec![],
884 },
885 ..Default::default()
886 };
887 bob_store.save_changes(bob_changes).await.unwrap();
888 bob_store.save_devices(vec![alice_device]);
889
890 let alice_store = VerificationStore {
891 inner: Arc::new(CryptoStoreWrapper::new(
892 alice.user_id(),
893 alice.device_id(),
894 alice_store,
895 )),
896 account: alice.static_data.clone(),
897 private_identity: alice_private_identity.into(),
898 };
899
900 let bob_store = VerificationStore {
901 account: bob.static_data.clone(),
902 inner: Arc::new(CryptoStoreWrapper::new(bob.user_id(), bob.device_id(), bob_store)),
903 private_identity: bob_private_identity.into(),
904 };
905
906 (alice, alice_store, bob, bob_store)
907 }
908}