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