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