1use std::{
16 collections::{BTreeMap, BTreeSet, HashMap},
17 default::Default,
18};
19
20use itertools::{Either, Itertools};
21use matrix_sdk_common::deserialized_responses::WithheldCode;
22use ruma::{DeviceId, OwnedDeviceId, OwnedUserId, UserId};
23use serde::{Deserialize, Serialize};
24use tracing::{debug, instrument, trace};
25
26use super::OutboundGroupSession;
27#[cfg(doc)]
28use crate::{Device, UserIdentity};
29use crate::{
30 DeviceData, EncryptionSettings, LocalTrust, OlmError, OwnUserIdentityData, UserIdentityData,
31 error::{OlmResult, SessionRecipientCollectionError},
32 olm::ShareInfo,
33 store::Store,
34};
35
36#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
39#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
40#[serde(from = "CollectStrategyDeserializationHelper")]
41pub enum CollectStrategy {
42 #[default]
51 AllDevices,
52
53 ErrorOnVerifiedUserProblem,
72
73 IdentityBasedStrategy,
85
86 OnlyTrustedDevices,
102}
103
104impl CollectStrategy {
105 pub const fn new_identity_based() -> Self {
107 CollectStrategy::IdentityBasedStrategy
108 }
109}
110
111#[derive(Deserialize)]
113enum CollectStrategyDeserializationHelper {
114 DeviceBasedStrategy {
117 #[serde(default)]
118 error_on_verified_user_problem: bool,
119
120 #[serde(default)]
121 only_allow_trusted_devices: bool,
122 },
123
124 AllDevices,
125 ErrorOnVerifiedUserProblem,
126 IdentityBasedStrategy,
127 OnlyTrustedDevices,
128}
129
130impl From<CollectStrategyDeserializationHelper> for CollectStrategy {
131 fn from(value: CollectStrategyDeserializationHelper) -> Self {
132 use CollectStrategyDeserializationHelper::*;
133
134 match value {
135 DeviceBasedStrategy {
136 only_allow_trusted_devices: true,
137 error_on_verified_user_problem: _,
138 } => CollectStrategy::OnlyTrustedDevices,
139 DeviceBasedStrategy {
140 only_allow_trusted_devices: false,
141 error_on_verified_user_problem: true,
142 } => CollectStrategy::ErrorOnVerifiedUserProblem,
143 DeviceBasedStrategy {
144 only_allow_trusted_devices: false,
145 error_on_verified_user_problem: false,
146 } => CollectStrategy::AllDevices,
147
148 AllDevices => CollectStrategy::AllDevices,
149 ErrorOnVerifiedUserProblem => CollectStrategy::ErrorOnVerifiedUserProblem,
150 IdentityBasedStrategy => CollectStrategy::IdentityBasedStrategy,
151 OnlyTrustedDevices => CollectStrategy::OnlyTrustedDevices,
152 }
153 }
154}
155
156#[derive(Debug, Default)]
163pub(crate) struct CollectRecipientsResult {
164 pub should_rotate: bool,
166 pub devices: BTreeMap<OwnedUserId, Vec<DeviceData>>,
168 pub withheld_devices: Vec<(DeviceData, WithheldCode)>,
171}
172
173#[instrument(skip_all)]
180pub(crate) async fn collect_session_recipients(
181 store: &Store,
182 users: impl Iterator<Item = &UserId>,
183 settings: &EncryptionSettings,
184 outbound: &OutboundGroupSession,
185) -> OlmResult<CollectRecipientsResult> {
186 let mut result = collect_recipients_for_share_strategy(
187 store,
188 users,
189 &settings.sharing_strategy,
190 Some(outbound),
191 )
192 .await?;
193
194 let device_removed = result.should_rotate;
204
205 let visibility_changed = outbound.settings().history_visibility != settings.history_visibility;
206 let algorithm_changed = outbound.settings().algorithm != settings.algorithm;
207
208 result.should_rotate = device_removed || visibility_changed || algorithm_changed;
209
210 if result.should_rotate {
211 debug!(
212 device_removed,
213 visibility_changed, algorithm_changed, "Rotating room key to protect room history",
214 );
215 }
216
217 Ok(result)
218}
219
220pub(crate) async fn collect_recipients_for_share_strategy(
230 store: &Store,
231 users: impl Iterator<Item = &UserId>,
232 share_strategy: &CollectStrategy,
233 outbound: Option<&OutboundGroupSession>,
234) -> OlmResult<CollectRecipientsResult> {
235 let users: BTreeSet<&UserId> = users.collect();
236 trace!(?users, ?share_strategy, "Calculating group session recipients");
237
238 let mut result = CollectRecipientsResult::default();
239 let mut verified_users_with_new_identities: Vec<OwnedUserId> = Default::default();
240
241 if let Some(outbound) = outbound {
245 let view = outbound.sharing_view();
246 let users_shared_with = view.shared_with_users().collect::<BTreeSet<_>>();
247 let left_users = users_shared_with.difference(&users).collect::<BTreeSet<_>>();
248 if !left_users.is_empty() {
249 trace!(?left_users, "Some users have left the chat: session must be rotated");
250 result.should_rotate = true;
251 }
252 }
253
254 let own_identity = store.get_user_identity(store.user_id()).await?.and_then(|i| i.into_own());
255
256 match share_strategy {
258 CollectStrategy::AllDevices => {
259 for user_id in users {
260 trace!(?user_id, "CollectStrategy::AllDevices: Considering recipient devices",);
261 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
262 let device_owner_identity = store.get_user_identity(user_id).await?;
263
264 let recipient_devices = split_devices_for_user_for_all_devices_strategy(
265 user_devices,
266 &own_identity,
267 &device_owner_identity,
268 );
269 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
270 }
271 }
272 CollectStrategy::ErrorOnVerifiedUserProblem => {
273 let mut unsigned_devices_of_verified_users: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>> =
274 Default::default();
275
276 for user_id in users {
277 trace!(
278 ?user_id,
279 "CollectStrategy::ErrorOnVerifiedUserProblem: Considering recipient devices"
280 );
281 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
282
283 let device_owner_identity = store.get_user_identity(user_id).await?;
284
285 if has_identity_verification_violation(
286 own_identity.as_ref(),
287 device_owner_identity.as_ref(),
288 ) {
289 verified_users_with_new_identities.push(user_id.to_owned());
290 continue;
292 }
293
294 let recipient_devices =
295 split_devices_for_user_for_error_on_verified_user_problem_strategy(
296 user_devices,
297 &own_identity,
298 &device_owner_identity,
299 );
300
301 match recipient_devices {
302 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices) => {
303 unsigned_devices_of_verified_users.insert(user_id.to_owned(), devices);
304 }
305 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices) => {
306 update_recipients_for_user(
307 &mut result,
308 outbound,
309 user_id,
310 recipient_devices,
311 );
312 }
313 }
314 }
315
316 if !unsigned_devices_of_verified_users.is_empty() {
320 return Err(OlmError::SessionRecipientCollectionError(
321 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
322 unsigned_devices_of_verified_users,
323 ),
324 ));
325 }
326 }
327 CollectStrategy::IdentityBasedStrategy => {
328 match &own_identity {
331 None => {
332 return Err(OlmError::SessionRecipientCollectionError(
333 SessionRecipientCollectionError::CrossSigningNotSetup,
334 ));
335 }
336 Some(identity) if !identity.is_verified() => {
337 return Err(OlmError::SessionRecipientCollectionError(
338 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
339 ));
340 }
341 Some(_) => (),
342 }
343
344 for user_id in users {
345 trace!(
346 ?user_id,
347 "CollectStrategy::IdentityBasedStrategy: Considering recipient devices"
348 );
349 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
350
351 let device_owner_identity = store.get_user_identity(user_id).await?;
352
353 if has_identity_verification_violation(
354 own_identity.as_ref(),
355 device_owner_identity.as_ref(),
356 ) {
357 verified_users_with_new_identities.push(user_id.to_owned());
358 continue;
360 }
361
362 let recipient_devices = split_devices_for_user_for_identity_based_strategy(
363 user_devices,
364 &device_owner_identity,
365 );
366
367 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
368 }
369 }
370
371 CollectStrategy::OnlyTrustedDevices => {
372 for user_id in users {
373 trace!(
374 ?user_id,
375 "CollectStrategy::OnlyTrustedDevices: Considering recipient devices"
376 );
377 let user_devices = store.get_device_data_for_user_filtered(user_id).await?;
378 let device_owner_identity = store.get_user_identity(user_id).await?;
379
380 let recipient_devices = split_devices_for_user_for_only_trusted_devices(
381 user_devices,
382 &own_identity,
383 &device_owner_identity,
384 );
385
386 update_recipients_for_user(&mut result, outbound, user_id, recipient_devices);
387 }
388 }
389 }
390
391 if !verified_users_with_new_identities.is_empty() {
394 return Err(OlmError::SessionRecipientCollectionError(
395 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
396 verified_users_with_new_identities,
397 ),
398 ));
399 }
400
401 trace!(result.should_rotate, "Done calculating group session recipients");
402
403 Ok(result)
404}
405
406fn update_recipients_for_user(
409 recipients: &mut CollectRecipientsResult,
410 outbound: Option<&OutboundGroupSession>,
411 user_id: &UserId,
412 recipient_devices: RecipientDevicesForUser,
413) {
414 if let Some(outbound) = outbound
419 && !recipients.should_rotate
420 {
421 recipients.should_rotate =
422 is_session_overshared_for_user(outbound, user_id, &recipient_devices.allowed_devices)
423 }
424
425 recipients
426 .devices
427 .entry(user_id.to_owned())
428 .or_default()
429 .extend(recipient_devices.allowed_devices);
430 recipients.withheld_devices.extend(recipient_devices.denied_devices_with_code);
431}
432
433fn is_session_overshared_for_user(
449 outbound_session: &OutboundGroupSession,
450 user_id: &UserId,
451 recipient_devices: &[DeviceData],
452) -> bool {
453 let recipient_device_ids: BTreeSet<&DeviceId> =
455 recipient_devices.iter().map(|d| d.device_id()).collect();
456
457 let view = outbound_session.sharing_view();
458 let newly_deleted_or_blacklisted: BTreeSet<&DeviceId> = view
459 .iter_shares(Some(user_id), None)
460 .filter_map(|(_user_id, device_id, info)| {
461 if matches!(info, ShareInfo::Shared(_)) && !recipient_device_ids.contains(device_id) {
465 Some(device_id)
466 } else {
467 None
468 }
469 })
470 .collect();
471
472 let should_rotate = !newly_deleted_or_blacklisted.is_empty();
473 if should_rotate {
474 debug!(
475 "Rotating a room key due to these devices being deleted/blacklisted {:?}",
476 newly_deleted_or_blacklisted,
477 );
478 }
479 should_rotate
480}
481
482#[cfg(feature = "experimental-send-custom-to-device")]
483pub(crate) async fn split_devices_for_share_strategy(
485 store: &Store,
486 devices: Vec<DeviceData>,
487 share_strategy: CollectStrategy,
488) -> OlmResult<(Vec<DeviceData>, Vec<(DeviceData, WithheldCode)>)> {
489 let own_identity = store.get_user_identity(store.user_id()).await?.and_then(|i| i.into_own());
490
491 let mut verified_users_with_new_identities: BTreeSet<OwnedUserId> = Default::default();
492
493 let mut allowed_devices: Vec<DeviceData> = Default::default();
494 let mut blocked_devices: Vec<(DeviceData, WithheldCode)> = Default::default();
495
496 let mut user_identities_cache: BTreeMap<OwnedUserId, Option<UserIdentityData>> =
497 Default::default();
498 let mut get_user_identity = async move |user_id| -> OlmResult<_> {
499 match user_identities_cache.get(user_id) {
500 Some(user_identity) => Ok(user_identity.clone()),
501 None => {
502 let user_identity = store.get_user_identity(user_id).await?;
503 user_identities_cache.insert(user_id.to_owned(), user_identity.clone());
504 Ok(user_identity)
505 }
506 }
507 };
508
509 match share_strategy {
510 CollectStrategy::AllDevices => {
511 for device in devices.iter() {
512 let user_id = device.user_id();
513 let device_owner_identity = get_user_identity(user_id).await?;
514
515 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
516 device,
517 &own_identity,
518 &device_owner_identity,
519 ) {
520 blocked_devices.push((device.clone(), withheld_code));
521 } else {
522 allowed_devices.push(device.clone());
523 }
524 }
525 }
526
527 CollectStrategy::ErrorOnVerifiedUserProblem => {
528 let mut unsigned_devices_of_verified_users: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>> =
534 Default::default();
535 let mut add_device_to_unsigned_devices_map = |user_id: &UserId, device: &DeviceData| {
536 let device_id = device.device_id().to_owned();
537 if let Some(devices) = unsigned_devices_of_verified_users.get_mut(user_id) {
538 devices.push(device_id);
539 } else {
540 unsigned_devices_of_verified_users.insert(user_id.to_owned(), vec![device_id]);
541 }
542 };
543
544 for device in devices.iter() {
545 let user_id = device.user_id();
546 let device_owner_identity = get_user_identity(user_id).await?;
547
548 if has_identity_verification_violation(
549 own_identity.as_ref(),
550 device_owner_identity.as_ref(),
551 ) {
552 verified_users_with_new_identities.insert(user_id.to_owned());
553 } else {
554 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
555 device,
556 own_identity.as_ref(),
557 device_owner_identity.as_ref(),
558 ) {
559 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
560 allowed_devices.push(device.clone())
561 }
562 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
563 blocked_devices.push((device.clone(), code))
564 }
565 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
566 add_device_to_unsigned_devices_map(user_id, device);
567 }
568 }
569 }
570 }
571
572 if !unsigned_devices_of_verified_users.is_empty() {
573 return Err(OlmError::SessionRecipientCollectionError(
574 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
575 unsigned_devices_of_verified_users,
576 ),
577 ));
578 }
579 }
580
581 CollectStrategy::IdentityBasedStrategy => {
582 match &own_identity {
585 None => {
586 return Err(OlmError::SessionRecipientCollectionError(
587 SessionRecipientCollectionError::CrossSigningNotSetup,
588 ));
589 }
590 Some(identity) if !identity.is_verified() => {
591 return Err(OlmError::SessionRecipientCollectionError(
592 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
593 ));
594 }
595 Some(_) => (),
596 }
597
598 for device in devices.iter() {
599 let user_id = device.user_id();
600 let device_owner_identity = get_user_identity(user_id).await?;
601
602 if has_identity_verification_violation(
603 own_identity.as_ref(),
604 device_owner_identity.as_ref(),
605 ) {
606 verified_users_with_new_identities.insert(user_id.to_owned());
607 } else if let Some(device_owner_identity) = device_owner_identity {
608 if let Some(withheld_code) =
609 withheld_code_for_device_with_owner_for_identity_based_strategy(
610 device,
611 &device_owner_identity,
612 )
613 {
614 blocked_devices.push((device.clone(), withheld_code));
615 } else {
616 allowed_devices.push(device.clone());
617 }
618 } else {
619 panic!("Should have verification violation if device_owner_identity is None")
620 }
621 }
622 }
623
624 CollectStrategy::OnlyTrustedDevices => {
625 for device in devices.iter() {
626 let user_id = device.user_id();
627 let device_owner_identity = get_user_identity(user_id).await?;
628
629 if let Some(withheld_code) =
630 withheld_code_for_device_for_only_trusted_devices_strategy(
631 device,
632 &own_identity,
633 &device_owner_identity,
634 )
635 {
636 blocked_devices.push((device.clone(), withheld_code));
637 } else {
638 allowed_devices.push(device.clone());
639 }
640 }
641 }
642 }
643
644 if !verified_users_with_new_identities.is_empty() {
645 return Err(OlmError::SessionRecipientCollectionError(
646 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
647 verified_users_with_new_identities.into_iter().collect(),
648 ),
649 ));
650 }
651
652 Ok((allowed_devices, blocked_devices))
653}
654
655pub(crate) async fn withheld_code_for_device_for_share_strategy(
656 device: &DeviceData,
657 share_strategy: CollectStrategy,
658 own_identity: &Option<OwnUserIdentityData>,
659 device_owner_identity: &Option<UserIdentityData>,
660) -> OlmResult<Option<WithheldCode>> {
661 match share_strategy {
662 CollectStrategy::AllDevices => Ok(withheld_code_for_device_for_all_devices_strategy(
663 device,
664 own_identity,
665 device_owner_identity,
666 )),
667 CollectStrategy::ErrorOnVerifiedUserProblem => {
668 if has_identity_verification_violation(
669 own_identity.as_ref(),
670 device_owner_identity.as_ref(),
671 ) {
672 return Err(OlmError::SessionRecipientCollectionError(
673 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
674 device.user_id().to_owned(),
675 ]),
676 ));
677 }
678 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
679 device,
680 own_identity.as_ref(),
681 device_owner_identity.as_ref(),
682 ) {
683 ErrorOnVerifiedUserProblemDeviceDecision::Ok => Ok(None),
684 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => Ok(Some(code)),
685 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
686 Err(OlmError::SessionRecipientCollectionError(
687 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
688 BTreeMap::from([(
689 device.user_id().to_owned(),
690 vec![device.device_id().to_owned()],
691 )]),
692 ),
693 ))
694 }
695 }
696 }
697 CollectStrategy::IdentityBasedStrategy => {
698 match &own_identity {
701 None => {
702 return Err(OlmError::SessionRecipientCollectionError(
703 SessionRecipientCollectionError::CrossSigningNotSetup,
704 ));
705 }
706 Some(identity) if !identity.is_verified() => {
707 return Err(OlmError::SessionRecipientCollectionError(
708 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
709 ));
710 }
711 Some(_) => (),
712 }
713
714 if has_identity_verification_violation(
715 own_identity.as_ref(),
716 device_owner_identity.as_ref(),
717 ) {
718 Err(OlmError::SessionRecipientCollectionError(
719 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
720 device.user_id().to_owned(),
721 ]),
722 ))
723 } else if let Some(device_owner_identity) = device_owner_identity {
724 Ok(withheld_code_for_device_with_owner_for_identity_based_strategy(
725 device,
726 device_owner_identity,
727 ))
728 } else {
729 panic!("Should have verification violation if device_owner_identity is None")
730 }
731 }
732 CollectStrategy::OnlyTrustedDevices => {
733 Ok(withheld_code_for_device_for_only_trusted_devices_strategy(
734 device,
735 own_identity,
736 device_owner_identity,
737 ))
738 }
739 }
740}
741
742#[derive(Default)]
749struct RecipientDevicesForUser {
750 allowed_devices: Vec<DeviceData>,
752 denied_devices_with_code: Vec<(DeviceData, WithheldCode)>,
754}
755
756enum ErrorOnVerifiedUserProblemResult {
759 UnsignedDevicesOfVerifiedUser(Vec<OwnedDeviceId>),
763
764 Devices(RecipientDevicesForUser),
766}
767
768fn split_devices_for_user_for_all_devices_strategy(
771 user_devices: HashMap<OwnedDeviceId, DeviceData>,
772 own_identity: &Option<OwnUserIdentityData>,
773 device_owner_identity: &Option<UserIdentityData>,
774) -> RecipientDevicesForUser {
775 let (left, right) = user_devices.into_values().partition_map(|d| {
776 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
777 &d,
778 own_identity,
779 device_owner_identity,
780 ) {
781 Either::Right((d, withheld_code))
782 } else {
783 Either::Left(d)
784 }
785 });
786
787 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
788}
789
790fn withheld_code_for_device_for_all_devices_strategy(
794 device_data: &DeviceData,
795 own_identity: &Option<OwnUserIdentityData>,
796 device_owner_identity: &Option<UserIdentityData>,
797) -> Option<WithheldCode> {
798 if device_data.is_blacklisted() {
799 Some(WithheldCode::Blacklisted)
800 } else if device_data.is_dehydrated()
801 && should_withhold_to_dehydrated_device(
802 device_data,
803 own_identity.as_ref(),
804 device_owner_identity.as_ref(),
805 )
806 {
807 Some(WithheldCode::Unverified)
808 } else {
809 None
810 }
811}
812
813fn should_withhold_to_dehydrated_device(
822 device: &DeviceData,
823 own_identity: Option<&OwnUserIdentityData>,
824 device_owner_identity: Option<&UserIdentityData>,
825) -> bool {
826 device_owner_identity.is_none_or(|owner_id| {
827 !device.is_cross_signed_by_owner(owner_id) ||
829
830 (owner_id.was_previously_verified() && !is_user_verified(own_identity, owner_id))
832 })
833}
834
835fn split_devices_for_user_for_error_on_verified_user_problem_strategy(
848 user_devices: HashMap<OwnedDeviceId, DeviceData>,
849 own_identity: &Option<OwnUserIdentityData>,
850 device_owner_identity: &Option<UserIdentityData>,
851) -> ErrorOnVerifiedUserProblemResult {
852 let mut recipient_devices = RecipientDevicesForUser::default();
853
854 let mut unsigned_devices_of_verified_users: Option<Vec<OwnedDeviceId>> = None;
857
858 for d in user_devices.into_values() {
859 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
860 &d,
861 own_identity.as_ref(),
862 device_owner_identity.as_ref(),
863 ) {
864 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
865 recipient_devices.allowed_devices.push(d)
866 }
867 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
868 recipient_devices.denied_devices_with_code.push((d, code))
869 }
870 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
871 unsigned_devices_of_verified_users
872 .get_or_insert_with(Vec::default)
873 .push(d.device_id().to_owned())
874 }
875 }
876 }
877
878 if let Some(devices) = unsigned_devices_of_verified_users {
879 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices)
880 } else {
881 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices)
882 }
883}
884
885enum ErrorOnVerifiedUserProblemDeviceDecision {
888 Ok,
889 Withhold(WithheldCode),
890 UnsignedOfVerified,
891}
892
893fn handle_device_for_user_for_error_on_verified_user_problem_strategy(
894 device: &DeviceData,
895 own_identity: Option<&OwnUserIdentityData>,
896 device_owner_identity: Option<&UserIdentityData>,
897) -> ErrorOnVerifiedUserProblemDeviceDecision {
898 if device.is_blacklisted() {
899 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Blacklisted)
900 } else if device.local_trust_state() == LocalTrust::Ignored {
901 ErrorOnVerifiedUserProblemDeviceDecision::Ok
903 } else if is_unsigned_device_of_verified_user(own_identity, device_owner_identity, device) {
904 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified
905 } else if device.is_dehydrated()
906 && device_owner_identity.is_none_or(|owner_id| {
907 !device.is_cross_signed_by_owner(owner_id)
910 })
911 {
912 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Unverified)
913 } else {
914 ErrorOnVerifiedUserProblemDeviceDecision::Ok
915 }
916}
917
918fn split_devices_for_user_for_identity_based_strategy(
919 user_devices: HashMap<OwnedDeviceId, DeviceData>,
920 device_owner_identity: &Option<UserIdentityData>,
921) -> RecipientDevicesForUser {
922 match device_owner_identity {
923 None => {
924 RecipientDevicesForUser {
927 allowed_devices: Vec::default(),
928 denied_devices_with_code: user_devices
929 .into_values()
930 .map(|d| (d, WithheldCode::Unverified))
931 .collect(),
932 }
933 }
934 Some(device_owner_identity) => {
935 let (recipients, withheld_recipients): (
937 Vec<DeviceData>,
938 Vec<(DeviceData, WithheldCode)>,
939 ) = user_devices.into_values().partition_map(|d| {
940 if let Some(withheld_code) =
941 withheld_code_for_device_with_owner_for_identity_based_strategy(
942 &d,
943 device_owner_identity,
944 )
945 {
946 Either::Right((d, withheld_code))
947 } else {
948 Either::Left(d)
949 }
950 });
951 RecipientDevicesForUser {
952 allowed_devices: recipients,
953 denied_devices_with_code: withheld_recipients,
954 }
955 }
956 }
957}
958
959fn withheld_code_for_device_with_owner_for_identity_based_strategy(
963 device_data: &DeviceData,
964 device_owner_identity: &UserIdentityData,
965) -> Option<WithheldCode> {
966 if device_data.is_cross_signed_by_owner(device_owner_identity) {
967 None
968 } else {
969 Some(WithheldCode::Unverified)
970 }
971}
972
973fn split_devices_for_user_for_only_trusted_devices(
976 user_devices: HashMap<OwnedDeviceId, DeviceData>,
977 own_identity: &Option<OwnUserIdentityData>,
978 device_owner_identity: &Option<UserIdentityData>,
979) -> RecipientDevicesForUser {
980 let (left, right) = user_devices.into_values().partition_map(|d| {
981 if let Some(withheld_code) = withheld_code_for_device_for_only_trusted_devices_strategy(
982 &d,
983 own_identity,
984 device_owner_identity,
985 ) {
986 Either::Right((d, withheld_code))
987 } else {
988 Either::Left(d)
989 }
990 });
991 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
992}
993
994fn withheld_code_for_device_for_only_trusted_devices_strategy(
998 device_data: &DeviceData,
999 own_identity: &Option<OwnUserIdentityData>,
1000 device_owner_identity: &Option<UserIdentityData>,
1001) -> Option<WithheldCode> {
1002 match (
1003 device_data.local_trust_state(),
1004 device_data.is_cross_signing_trusted(own_identity, device_owner_identity),
1005 ) {
1006 (LocalTrust::BlackListed, _) => Some(WithheldCode::Blacklisted),
1007 (LocalTrust::Ignored | LocalTrust::Verified, _) => None,
1008 (LocalTrust::Unset, false) => Some(WithheldCode::Unverified),
1009 (LocalTrust::Unset, true) => None,
1010 }
1011}
1012
1013fn is_unsigned_device_of_verified_user(
1014 own_identity: Option<&OwnUserIdentityData>,
1015 device_owner_identity: Option<&UserIdentityData>,
1016 device_data: &DeviceData,
1017) -> bool {
1018 device_owner_identity.is_some_and(|device_owner_identity| {
1019 is_user_verified(own_identity, device_owner_identity)
1020 && !device_data.is_cross_signed_by_owner(device_owner_identity)
1021 })
1022}
1023
1024fn has_identity_verification_violation(
1031 own_identity: Option<&OwnUserIdentityData>,
1032 device_owner_identity: Option<&UserIdentityData>,
1033) -> bool {
1034 device_owner_identity.is_some_and(|device_owner_identity| {
1035 device_owner_identity.was_previously_verified()
1036 && !is_user_verified(own_identity, device_owner_identity)
1037 })
1038}
1039
1040fn is_user_verified(
1041 own_identity: Option<&OwnUserIdentityData>,
1042 user_identity: &UserIdentityData,
1043) -> bool {
1044 match user_identity {
1045 UserIdentityData::Own(own_identity) => own_identity.is_verified(),
1046 UserIdentityData::Other(other_identity) => {
1047 own_identity.is_some_and(|oi| oi.is_identity_verified(other_identity))
1048 }
1049 }
1050}
1051
1052#[cfg(test)]
1053mod tests {
1054 use std::{collections::BTreeMap, iter, ops::Deref, sync::Arc};
1055
1056 use assert_matches::assert_matches;
1057 use assert_matches2::assert_let;
1058 use insta::{assert_snapshot, with_settings};
1059 use matrix_sdk_common::deserialized_responses::WithheldCode;
1060 use matrix_sdk_test::{
1061 async_test, test_json,
1062 test_json::keys_query_sets::{
1063 IdentityChangeDataSet, KeyDistributionTestData, MaloIdentityChangeDataSet,
1064 VerificationViolationTestData,
1065 },
1066 };
1067 use ruma::{
1068 DeviceId, TransactionId, UserId, device_id,
1069 events::{dummy::ToDeviceDummyEventContent, room::history_visibility::HistoryVisibility},
1070 room_id,
1071 };
1072 use serde_json::json;
1073
1074 #[cfg(feature = "experimental-send-custom-to-device")]
1075 use super::split_devices_for_share_strategy;
1076 use crate::{
1077 CrossSigningKeyExport, DeviceData, EncryptionSettings, LocalTrust, OlmError, OlmMachine,
1078 error::SessionRecipientCollectionError,
1079 olm::{OutboundGroupSession, ShareInfo},
1080 session_manager::{
1081 CollectStrategy,
1082 group_sessions::share_strategy::{
1083 collect_session_recipients, withheld_code_for_device_for_share_strategy,
1084 },
1085 },
1086 store::caches::SequenceNumber,
1087 testing::simulate_key_query_response_for_verification,
1088 types::requests::ToDeviceRequest,
1089 };
1090
1091 async fn test_machine() -> OlmMachine {
1095 use KeyDistributionTestData as DataSet;
1096
1097 let machine = OlmMachine::new(DataSet::me_id(), DataSet::me_device_id()).await;
1099 let keys_query = DataSet::me_keys_query_response();
1100 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1101
1102 machine
1104 .import_cross_signing_keys(CrossSigningKeyExport {
1105 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1106 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1107 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1108 })
1109 .await
1110 .unwrap();
1111
1112 machine
1113 }
1114
1115 async fn get_device_data(
1117 machine: &OlmMachine,
1118 user_id: &UserId,
1119 device_id: &DeviceId,
1120 ) -> DeviceData {
1121 machine.get_device(user_id, device_id, None).await.unwrap().unwrap().deref().clone()
1122 }
1123
1124 async fn get_own_identity_data(
1125 machine: &OlmMachine,
1126 user_id: &UserId,
1127 ) -> Option<crate::OwnUserIdentityData> {
1128 machine
1129 .get_identity(user_id, None)
1130 .await
1131 .unwrap()
1132 .and_then(|i| i.own())
1133 .map(|i| i.deref().clone())
1134 }
1135
1136 async fn get_user_identity_data(
1137 machine: &OlmMachine,
1138 user_id: &UserId,
1139 ) -> Option<crate::UserIdentityData> {
1140 use crate::{UserIdentity, identities::user::UserIdentityData};
1141 machine.get_identity(user_id, None).await.unwrap().map(|i| match i {
1142 UserIdentity::Own(i) => UserIdentityData::Own(i.deref().clone()),
1143 UserIdentity::Other(i) => UserIdentityData::Other(i.deref().clone()),
1144 })
1145 }
1146
1147 async fn import_known_users_to_test_machine(machine: &OlmMachine) {
1150 let keys_query = KeyDistributionTestData::dan_keys_query_response();
1151 let txn_id = TransactionId::new();
1152 machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap();
1153
1154 let txn_id_dave = TransactionId::new();
1155 let keys_query_dave = KeyDistributionTestData::dave_keys_query_response();
1156 machine.mark_request_as_sent(&txn_id_dave, &keys_query_dave).await.unwrap();
1157
1158 let txn_id_good = TransactionId::new();
1159 let keys_query_good = KeyDistributionTestData::good_keys_query_response();
1160 machine.mark_request_as_sent(&txn_id_good, &keys_query_good).await.unwrap();
1161 }
1162
1163 #[test]
1166 #[cfg(not(feature = "experimental-encrypted-state-events"))]
1167 fn test_serialize_device_based_strategy() {
1168 let encryption_settings = all_devices_strategy_settings();
1169 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1170 with_settings!({prepend_module_to_snapshot => false}, {
1171 assert_snapshot!(serialized)
1172 });
1173 }
1174
1175 #[test]
1179 #[cfg(feature = "experimental-encrypted-state-events")]
1180 fn test_serialize_strategy_with_encrypted_state() {
1181 let encryption_settings = all_devices_strategy_settings();
1182 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1183 with_settings!({prepend_module_to_snapshot => false}, {
1184 assert_snapshot!(serialized)
1185 });
1186 }
1187
1188 #[test]
1192 fn test_deserialize_old_device_based_strategy() {
1193 let settings: EncryptionSettings = serde_json::from_value(json!({
1194 "algorithm": "m.megolm.v1.aes-sha2",
1195 "rotation_period":{"secs":604800,"nanos":0},
1196 "rotation_period_msgs":100,
1197 "history_visibility":"shared",
1198 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":false}},
1199 })).unwrap();
1200 assert_matches!(settings.sharing_strategy, CollectStrategy::AllDevices);
1201 }
1202
1203 #[test]
1207 fn test_deserialize_old_error_on_verified_user_problem() {
1208 let settings: EncryptionSettings = serde_json::from_value(json!({
1209 "algorithm": "m.megolm.v1.aes-sha2",
1210 "rotation_period":{"secs":604800,"nanos":0},
1211 "rotation_period_msgs":100,
1212 "history_visibility":"shared",
1213 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":true}},
1214 })).unwrap();
1215 assert_matches!(settings.sharing_strategy, CollectStrategy::ErrorOnVerifiedUserProblem);
1216 }
1217
1218 #[test]
1222 fn test_deserialize_old_only_trusted_devices_strategy() {
1223 let settings: EncryptionSettings = serde_json::from_value(json!({
1224 "algorithm": "m.megolm.v1.aes-sha2",
1225 "rotation_period":{"secs":604800,"nanos":0},
1226 "rotation_period_msgs":100,
1227 "history_visibility":"shared",
1228 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":true,"error_on_verified_user_problem":false}},
1229 })).unwrap();
1230 assert_matches!(settings.sharing_strategy, CollectStrategy::OnlyTrustedDevices);
1231 }
1232
1233 #[async_test]
1234 async fn test_share_with_per_device_strategy_to_all() {
1235 let machine = test_machine().await;
1236 import_known_users_to_test_machine(&machine).await;
1237
1238 let encryption_settings = all_devices_strategy_settings();
1239
1240 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1241
1242 let share_result = collect_session_recipients(
1243 machine.store(),
1244 vec![
1245 KeyDistributionTestData::dan_id(),
1246 KeyDistributionTestData::dave_id(),
1247 KeyDistributionTestData::good_id(),
1248 ]
1249 .into_iter(),
1250 &encryption_settings,
1251 &group_session,
1252 )
1253 .await
1254 .unwrap();
1255
1256 assert!(!share_result.should_rotate);
1257
1258 let dan_devices_shared =
1259 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1260 let dave_devices_shared =
1261 share_result.devices.get(KeyDistributionTestData::dave_id()).unwrap();
1262 let good_devices_shared =
1263 share_result.devices.get(KeyDistributionTestData::good_id()).unwrap();
1264
1265 assert_eq!(dan_devices_shared.len(), 2);
1267 assert_eq!(dave_devices_shared.len(), 1);
1268 assert_eq!(good_devices_shared.len(), 2);
1269
1270 #[cfg(feature = "experimental-send-custom-to-device")]
1271 {
1272 let mut all_devices = dan_devices_shared.clone();
1276 all_devices.append(&mut dave_devices_shared.clone());
1277 all_devices.append(&mut good_devices_shared.clone());
1278
1279 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1280 machine.store(),
1281 all_devices,
1282 CollectStrategy::AllDevices,
1283 )
1284 .await
1285 .unwrap();
1286
1287 assert_eq!(shared_devices.len(), 5);
1288 assert_eq!(withheld_devices.len(), 0);
1289 }
1290
1291 let own_identity_data =
1292 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1293 let dan_identity_data =
1294 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1295
1296 assert_eq!(
1297 withheld_code_for_device_for_share_strategy(
1298 &get_device_data(
1299 &machine,
1300 KeyDistributionTestData::dan_id(),
1301 KeyDistributionTestData::dan_signed_device_id()
1302 )
1303 .await,
1304 CollectStrategy::AllDevices,
1305 &own_identity_data,
1306 &dan_identity_data,
1307 )
1308 .await
1309 .unwrap(),
1310 None,
1311 );
1312 }
1313
1314 #[async_test]
1315 async fn test_share_with_only_trusted_strategy() {
1316 let machine = test_machine().await;
1317 import_known_users_to_test_machine(&machine).await;
1318
1319 let encryption_settings = EncryptionSettings {
1320 sharing_strategy: CollectStrategy::OnlyTrustedDevices,
1321 ..Default::default()
1322 };
1323
1324 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1325
1326 let share_result = collect_session_recipients(
1327 machine.store(),
1328 vec![
1329 KeyDistributionTestData::dan_id(),
1330 KeyDistributionTestData::dave_id(),
1331 KeyDistributionTestData::good_id(),
1332 ]
1333 .into_iter(),
1334 &encryption_settings,
1335 &group_session,
1336 )
1337 .await
1338 .unwrap();
1339
1340 assert!(!share_result.should_rotate);
1341
1342 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
1343 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
1344 assert!(dave_devices_shared.unwrap().is_empty());
1346 assert!(good_devices_shared.unwrap().is_empty());
1347
1348 let dan_devices_shared =
1351 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1352
1353 assert_eq!(dan_devices_shared.len(), 1);
1354 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
1355 assert_eq!(
1356 dan_device_that_will_get_the_key.device_id().as_str(),
1357 KeyDistributionTestData::dan_signed_device_id()
1358 );
1359
1360 let (_, code) = share_result
1362 .withheld_devices
1363 .iter()
1364 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
1365 .expect("This dan's device should receive a withheld code");
1366
1367 assert_eq!(code, &WithheldCode::Unverified);
1368
1369 let (_, code) = share_result
1370 .withheld_devices
1371 .iter()
1372 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
1373 .expect("This daves's device should receive a withheld code");
1374
1375 assert_eq!(code, &WithheldCode::Unverified);
1376
1377 #[cfg(feature = "experimental-send-custom-to-device")]
1378 {
1379 let all_devices: Vec<DeviceData> = vec![
1380 get_device_data(
1381 &machine,
1382 KeyDistributionTestData::dan_id(),
1383 KeyDistributionTestData::dan_unsigned_device_id(),
1384 )
1385 .await,
1386 get_device_data(
1387 &machine,
1388 KeyDistributionTestData::dan_id(),
1389 KeyDistributionTestData::dan_signed_device_id(),
1390 )
1391 .await,
1392 get_device_data(
1393 &machine,
1394 KeyDistributionTestData::dave_id(),
1395 KeyDistributionTestData::dave_device_id(),
1396 )
1397 .await,
1398 get_device_data(
1399 &machine,
1400 KeyDistributionTestData::good_id(),
1401 KeyDistributionTestData::good_device_1_id(),
1402 )
1403 .await,
1404 get_device_data(
1405 &machine,
1406 KeyDistributionTestData::good_id(),
1407 KeyDistributionTestData::good_device_2_id(),
1408 )
1409 .await,
1410 ];
1411
1412 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1413 machine.store(),
1414 all_devices,
1415 CollectStrategy::OnlyTrustedDevices,
1416 )
1417 .await
1418 .unwrap();
1419
1420 assert_eq!(shared_devices.len(), 1);
1421 assert_eq!(
1422 shared_devices[0].device_id().as_str(),
1423 KeyDistributionTestData::dan_signed_device_id()
1424 );
1425
1426 assert_eq!(withheld_devices.len(), 4);
1427 assert_eq!(
1428 withheld_devices[0].0.device_id().as_str(),
1429 KeyDistributionTestData::dan_unsigned_device_id()
1430 );
1431 assert_eq!(withheld_devices[0].1, WithheldCode::Unverified);
1432 assert_eq!(
1433 withheld_devices[1].0.device_id().as_str(),
1434 KeyDistributionTestData::dave_device_id()
1435 );
1436 assert_eq!(withheld_devices[1].1, WithheldCode::Unverified);
1437 }
1438
1439 let own_identity_data =
1440 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1441 let dan_identity_data =
1442 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1443 let dave_identity_data =
1444 get_user_identity_data(&machine, KeyDistributionTestData::dave_id()).await;
1445
1446 assert_eq!(
1447 withheld_code_for_device_for_share_strategy(
1448 &get_device_data(
1449 &machine,
1450 KeyDistributionTestData::dan_id(),
1451 KeyDistributionTestData::dan_signed_device_id()
1452 )
1453 .await,
1454 CollectStrategy::OnlyTrustedDevices,
1455 &own_identity_data,
1456 &dan_identity_data,
1457 )
1458 .await
1459 .unwrap(),
1460 None,
1461 );
1462 assert_eq!(
1463 withheld_code_for_device_for_share_strategy(
1464 &get_device_data(
1465 &machine,
1466 KeyDistributionTestData::dan_id(),
1467 KeyDistributionTestData::dan_unsigned_device_id()
1468 )
1469 .await,
1470 CollectStrategy::OnlyTrustedDevices,
1471 &own_identity_data,
1472 &dan_identity_data,
1473 )
1474 .await
1475 .unwrap(),
1476 Some(WithheldCode::Unverified),
1477 );
1478 assert_eq!(
1479 withheld_code_for_device_for_share_strategy(
1480 &get_device_data(
1481 &machine,
1482 KeyDistributionTestData::dave_id(),
1483 KeyDistributionTestData::dave_device_id()
1484 )
1485 .await,
1486 CollectStrategy::OnlyTrustedDevices,
1487 &own_identity_data,
1488 &dave_identity_data,
1489 )
1490 .await
1491 .unwrap(),
1492 Some(WithheldCode::Unverified),
1493 );
1494 }
1495
1496 #[async_test]
1500 async fn test_error_on_unsigned_of_verified_users() {
1501 use VerificationViolationTestData as DataSet;
1502
1503 let machine = unsigned_of_verified_setup().await;
1505
1506 let carol_keys = DataSet::carol_keys_query_response_signed();
1508 machine.mark_request_as_sent(&TransactionId::new(), &carol_keys).await.unwrap();
1509
1510 let carol_identity =
1512 machine.get_identity(DataSet::carol_id(), None).await.unwrap().unwrap();
1513 assert!(carol_identity.other().unwrap().is_verified());
1514
1515 let carol_unsigned_device = machine
1516 .get_device(DataSet::carol_id(), DataSet::carol_unsigned_device_id(), None)
1517 .await
1518 .unwrap()
1519 .unwrap();
1520 assert!(!carol_unsigned_device.is_verified());
1521
1522 let encryption_settings = error_on_verification_problem_encryption_settings();
1524 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1525 let share_result = collect_session_recipients(
1526 machine.store(),
1527 vec![DataSet::bob_id(), DataSet::carol_id()].into_iter(),
1528 &encryption_settings,
1529 &group_session,
1530 )
1531 .await;
1532
1533 assert_let!(
1534 Err(OlmError::SessionRecipientCollectionError(
1535 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1536 )) = share_result
1537 );
1538
1539 assert_eq!(
1541 unverified_devices,
1542 BTreeMap::from([
1543 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1544 (
1545 DataSet::carol_id().to_owned(),
1546 vec![DataSet::carol_unsigned_device_id().to_owned()]
1547 ),
1548 ])
1549 );
1550
1551 #[cfg(feature = "experimental-send-custom-to-device")]
1552 {
1553 let all_devices = vec![
1554 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1555 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1556 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1557 .await,
1558 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_unsigned_device_id())
1559 .await,
1560 ];
1561
1562 let split_result = split_devices_for_share_strategy(
1563 machine.store(),
1564 all_devices,
1565 CollectStrategy::ErrorOnVerifiedUserProblem,
1566 )
1567 .await;
1568
1569 assert_let!(
1570 Err(OlmError::SessionRecipientCollectionError(
1571 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1572 unverified_devices
1573 )
1574 )) = split_result
1575 );
1576
1577 assert_eq!(
1579 unverified_devices,
1580 BTreeMap::from([
1581 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1582 (
1583 DataSet::carol_id().to_owned(),
1584 vec![DataSet::carol_unsigned_device_id().to_owned()]
1585 ),
1586 ])
1587 );
1588 }
1589
1590 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1591 let carol_identity_data = get_user_identity_data(&machine, DataSet::carol_id()).await;
1592
1593 assert_eq!(
1594 withheld_code_for_device_for_share_strategy(
1595 &get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1596 .await,
1597 CollectStrategy::ErrorOnVerifiedUserProblem,
1598 &own_identity_data,
1599 &carol_identity_data,
1600 )
1601 .await
1602 .unwrap(),
1603 None,
1604 );
1605 assert_let!(
1606 Err(OlmError::SessionRecipientCollectionError(
1607 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1608 )) = withheld_code_for_device_for_share_strategy(
1609 &get_device_data(
1610 &machine,
1611 DataSet::carol_id(),
1612 DataSet::carol_unsigned_device_id()
1613 )
1614 .await,
1615 CollectStrategy::ErrorOnVerifiedUserProblem,
1616 &own_identity_data,
1617 &carol_identity_data,
1618 )
1619 .await
1620 );
1621 }
1622
1623 #[async_test]
1627 async fn test_error_on_unsigned_of_verified_resolve_by_whitelisting() {
1628 use VerificationViolationTestData as DataSet;
1629
1630 let machine = unsigned_of_verified_setup().await;
1631
1632 machine
1634 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1635 .await
1636 .unwrap()
1637 .unwrap()
1638 .set_local_trust(LocalTrust::Ignored)
1639 .await
1640 .unwrap();
1641
1642 let encryption_settings = error_on_verification_problem_encryption_settings();
1643 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1644
1645 let share_result = collect_session_recipients(
1647 machine.store(),
1648 iter::once(DataSet::bob_id()),
1649 &encryption_settings,
1650 &group_session,
1651 )
1652 .await
1653 .unwrap();
1654
1655 assert_eq!(2, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1656 assert_eq!(0, share_result.withheld_devices.len());
1657
1658 #[cfg(feature = "experimental-send-custom-to-device")]
1659 {
1660 let all_devices = vec![
1661 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1662 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1663 ];
1664
1665 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1666 machine.store(),
1667 all_devices,
1668 CollectStrategy::ErrorOnVerifiedUserProblem,
1669 )
1670 .await
1671 .unwrap();
1672
1673 assert_eq!(shared_devices.len(), 2);
1674 assert_eq!(withheld_devices.len(), 0);
1675 }
1676
1677 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1678 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1679
1680 assert_eq!(
1681 withheld_code_for_device_for_share_strategy(
1682 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1683 CollectStrategy::ErrorOnVerifiedUserProblem,
1684 &own_identity_data,
1685 &bob_identity_data,
1686 )
1687 .await
1688 .unwrap(),
1689 None,
1690 );
1691 }
1692
1693 #[async_test]
1697 async fn test_error_on_unsigned_of_verified_resolve_by_blacklisting() {
1698 use VerificationViolationTestData as DataSet;
1699
1700 let machine = unsigned_of_verified_setup().await;
1701
1702 machine
1704 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1705 .await
1706 .unwrap()
1707 .unwrap()
1708 .set_local_trust(LocalTrust::BlackListed)
1709 .await
1710 .unwrap();
1711
1712 let encryption_settings = error_on_verification_problem_encryption_settings();
1713 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1714
1715 let share_result = collect_session_recipients(
1717 machine.store(),
1718 iter::once(DataSet::bob_id()),
1719 &encryption_settings,
1720 &group_session,
1721 )
1722 .await
1723 .unwrap();
1724
1725 assert_eq!(1, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1726 let withheld_list: Vec<_> = share_result
1727 .withheld_devices
1728 .iter()
1729 .map(|(d, code)| (d.device_id().to_owned(), code.clone()))
1730 .collect();
1731 assert_eq!(
1732 withheld_list,
1733 vec![(DataSet::bob_device_2_id().to_owned(), WithheldCode::Blacklisted)]
1734 );
1735
1736 let bob_device_2 =
1737 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await;
1738 #[cfg(feature = "experimental-send-custom-to-device")]
1739 {
1740 let bob_device_1 =
1741 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await;
1742 let all_devices = vec![bob_device_1.clone(), bob_device_2.clone()];
1743
1744 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1745 machine.store(),
1746 all_devices,
1747 CollectStrategy::ErrorOnVerifiedUserProblem,
1748 )
1749 .await
1750 .unwrap();
1751
1752 assert_eq!(shared_devices, vec![bob_device_1.clone()]);
1753 assert_eq!(withheld_devices, vec![(bob_device_2.clone(), WithheldCode::Blacklisted)]);
1754 }
1755
1756 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1757 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1758
1759 assert_eq!(
1760 withheld_code_for_device_for_share_strategy(
1761 &bob_device_2,
1762 CollectStrategy::ErrorOnVerifiedUserProblem,
1763 &own_identity_data,
1764 &bob_identity_data,
1765 )
1766 .await
1767 .unwrap(),
1768 Some(WithheldCode::Blacklisted),
1769 );
1770 }
1771
1772 #[async_test]
1776 async fn test_error_on_unsigned_of_verified_owner_is_us() {
1777 use VerificationViolationTestData as DataSet;
1778
1779 let machine = unsigned_of_verified_setup().await;
1780
1781 let mut own_keys = DataSet::own_keys_query_response_1().clone();
1783 own_keys.device_keys.insert(
1784 DataSet::own_id().to_owned(),
1785 BTreeMap::from([
1786 DataSet::own_signed_device_keys(),
1787 DataSet::own_unsigned_device_keys(),
1788 ]),
1789 );
1790 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1791
1792 let encryption_settings = error_on_verification_problem_encryption_settings();
1793 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1794 let share_result = collect_session_recipients(
1795 machine.store(),
1796 iter::once(DataSet::own_id()),
1797 &encryption_settings,
1798 &group_session,
1799 )
1800 .await;
1801
1802 assert_let!(
1803 Err(OlmError::SessionRecipientCollectionError(
1804 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1805 )) = share_result
1806 );
1807
1808 assert_eq!(
1810 unverified_devices,
1811 BTreeMap::from([(
1812 DataSet::own_id().to_owned(),
1813 vec![DataSet::own_unsigned_device_id()]
1814 ),])
1815 );
1816
1817 #[cfg(feature = "experimental-send-custom-to-device")]
1818 {
1819 let all_devices = vec![
1820 get_device_data(&machine, DataSet::own_id(), &DataSet::own_signed_device_id())
1821 .await,
1822 get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1823 .await,
1824 ];
1825
1826 let split_result = split_devices_for_share_strategy(
1827 machine.store(),
1828 all_devices,
1829 CollectStrategy::ErrorOnVerifiedUserProblem,
1830 )
1831 .await;
1832 assert_let!(
1833 Err(OlmError::SessionRecipientCollectionError(
1834 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1835 unverified_devices
1836 )
1837 )) = split_result
1838 );
1839
1840 assert_eq!(
1842 unverified_devices,
1843 BTreeMap::from([(
1844 DataSet::own_id().to_owned(),
1845 vec![DataSet::own_unsigned_device_id()]
1846 ),])
1847 );
1848 }
1849
1850 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1851 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
1852
1853 assert_let!(
1854 Err(OlmError::SessionRecipientCollectionError(
1855 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1856 )) = withheld_code_for_device_for_share_strategy(
1857 &get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1858 .await,
1859 CollectStrategy::ErrorOnVerifiedUserProblem,
1860 &own_identity_data,
1861 &own_user_identity_data,
1862 )
1863 .await
1864 );
1865 }
1866
1867 #[async_test]
1870 async fn test_should_not_error_on_unsigned_of_unverified() {
1871 use VerificationViolationTestData as DataSet;
1872
1873 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1874
1875 let own_keys = DataSet::own_keys_query_response_1();
1877 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1878
1879 machine
1881 .import_cross_signing_keys(CrossSigningKeyExport {
1882 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1883 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1884 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1885 })
1886 .await
1887 .unwrap();
1888
1889 let bob_keys = DataSet::bob_keys_query_response_rotated();
1891 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
1892
1893 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
1896 assert!(!bob_identity.other().unwrap().is_verified());
1897
1898 let bob_unsigned_device = machine
1899 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
1900 .await
1901 .unwrap()
1902 .unwrap();
1903 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1904
1905 let encryption_settings = error_on_verification_problem_encryption_settings();
1906 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1907 collect_session_recipients(
1908 machine.store(),
1909 iter::once(DataSet::bob_id()),
1910 &encryption_settings,
1911 &group_session,
1912 )
1913 .await
1914 .unwrap();
1915
1916 #[cfg(feature = "experimental-send-custom-to-device")]
1917 {
1918 let all_devices = vec![
1919 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1920 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1921 ];
1922
1923 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1924 machine.store(),
1925 all_devices,
1926 CollectStrategy::ErrorOnVerifiedUserProblem,
1927 )
1928 .await
1929 .unwrap();
1930
1931 assert_eq!(shared_devices.len(), 2);
1932 assert_eq!(withheld_devices.len(), 0);
1933 }
1934
1935 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1936 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1937
1938 assert_eq!(
1939 withheld_code_for_device_for_share_strategy(
1940 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1941 CollectStrategy::ErrorOnVerifiedUserProblem,
1942 &own_identity_data,
1943 &bob_identity_data,
1944 )
1945 .await
1946 .unwrap(),
1947 None,
1948 );
1949 }
1950
1951 #[async_test]
1954 async fn test_should_not_error_on_unsigned_of_signed_but_unverified() {
1955 use VerificationViolationTestData as DataSet;
1956
1957 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1958
1959 let keys_query = DataSet::own_keys_query_response_1();
1961 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1962
1963 let keys_query = DataSet::bob_keys_query_response_signed();
1965 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1966
1967 let bob_identity =
1970 machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap();
1971 assert!(
1972 bob_identity.own_identity.as_ref().unwrap().is_identity_signed(&bob_identity.inner)
1973 );
1974 assert!(!bob_identity.is_verified());
1975
1976 let bob_unsigned_device = machine
1977 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1978 .await
1979 .unwrap()
1980 .unwrap();
1981 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1982
1983 let encryption_settings = error_on_verification_problem_encryption_settings();
1985 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1986 collect_session_recipients(
1987 machine.store(),
1988 iter::once(DataSet::bob_id()),
1989 &encryption_settings,
1990 &group_session,
1991 )
1992 .await
1993 .unwrap();
1994
1995 #[cfg(feature = "experimental-send-custom-to-device")]
1996 {
1997 let all_devices = vec![
1998 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1999 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2000 ];
2001
2002 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
2003 machine.store(),
2004 all_devices,
2005 CollectStrategy::ErrorOnVerifiedUserProblem,
2006 )
2007 .await
2008 .unwrap();
2009
2010 assert_eq!(shared_devices.len(), 2);
2011 assert_eq!(withheld_devices.len(), 0);
2012 }
2013
2014 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2015 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2016
2017 assert_eq!(
2018 withheld_code_for_device_for_share_strategy(
2019 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2020 CollectStrategy::ErrorOnVerifiedUserProblem,
2021 &own_identity_data,
2022 &bob_identity_data,
2023 )
2024 .await
2025 .unwrap(),
2026 None,
2027 );
2028 }
2029
2030 #[async_test]
2034 async fn test_verified_user_changed_identity() {
2035 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2036
2037 let machine = unsigned_of_verified_setup().await;
2040
2041 let bob_keys = DataSet::bob_keys_query_response_rotated();
2043 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
2044
2045 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
2047 assert!(bob_identity.has_verification_violation());
2048
2049 let encryption_settings = error_on_verification_problem_encryption_settings();
2051 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2052 let share_result = collect_session_recipients(
2053 machine.store(),
2054 iter::once(DataSet::bob_id()),
2055 &encryption_settings,
2056 &group_session,
2057 )
2058 .await;
2059
2060 assert_let!(
2061 Err(OlmError::SessionRecipientCollectionError(
2062 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2063 )) = share_result
2064 );
2065 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2066
2067 #[cfg(feature = "experimental-send-custom-to-device")]
2068 {
2069 let all_devices = vec![
2070 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2071 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2072 ];
2073
2074 let split_result = split_devices_for_share_strategy(
2075 machine.store(),
2076 all_devices,
2077 CollectStrategy::ErrorOnVerifiedUserProblem,
2078 )
2079 .await;
2080 assert_let!(
2081 Err(OlmError::SessionRecipientCollectionError(
2082 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2083 )) = split_result
2084 );
2085 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2086 }
2087
2088 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2089 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2090
2091 assert_let!(
2092 Err(OlmError::SessionRecipientCollectionError(
2093 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2094 )) = withheld_code_for_device_for_share_strategy(
2095 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2096 CollectStrategy::ErrorOnVerifiedUserProblem,
2097 &own_identity_data,
2098 &bob_identity_data,
2099 )
2100 .await
2101 );
2102
2103 bob_identity.withdraw_verification().await.unwrap();
2105
2106 collect_session_recipients(
2107 machine.store(),
2108 iter::once(DataSet::bob_id()),
2109 &encryption_settings,
2110 &group_session,
2111 )
2112 .await
2113 .unwrap();
2114
2115 #[cfg(feature = "experimental-send-custom-to-device")]
2116 {
2117 let all_devices = vec![
2118 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2119 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2120 ];
2121
2122 split_devices_for_share_strategy(
2123 machine.store(),
2124 all_devices,
2125 CollectStrategy::ErrorOnVerifiedUserProblem,
2126 )
2127 .await
2128 .unwrap();
2129 }
2130
2131 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2132 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2133
2134 assert_eq!(
2135 withheld_code_for_device_for_share_strategy(
2136 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2137 CollectStrategy::ErrorOnVerifiedUserProblem,
2138 &own_identity_data,
2139 &bob_identity_data,
2140 )
2141 .await
2142 .unwrap(),
2143 None,
2144 );
2145 }
2146
2147 #[async_test]
2151 async fn test_own_verified_identity_changed() {
2152 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2153
2154 let machine = unsigned_of_verified_setup().await;
2156 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2157 assert!(own_identity.own().unwrap().is_verified());
2158
2159 let own_keys = DataSet::own_keys_query_response_2();
2161 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
2162
2163 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2164 assert!(!own_identity.is_verified());
2165
2166 let encryption_settings = error_on_verification_problem_encryption_settings();
2168 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2169 let share_result = collect_session_recipients(
2170 machine.store(),
2171 iter::once(DataSet::own_id()),
2172 &encryption_settings,
2173 &group_session,
2174 )
2175 .await;
2176
2177 assert_let!(
2178 Err(OlmError::SessionRecipientCollectionError(
2179 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2180 )) = share_result
2181 );
2182 assert_eq!(violating_users, vec![DataSet::own_id()]);
2183
2184 #[cfg(feature = "experimental-send-custom-to-device")]
2185 {
2186 let all_devices: Vec<DeviceData> =
2187 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2188
2189 let split_result = split_devices_for_share_strategy(
2190 machine.store(),
2191 all_devices,
2192 CollectStrategy::ErrorOnVerifiedUserProblem,
2193 )
2194 .await;
2195
2196 assert_let!(
2197 Err(OlmError::SessionRecipientCollectionError(
2198 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2199 )) = split_result
2200 );
2201 assert_eq!(violating_users, vec![DataSet::own_id()]);
2202 }
2203
2204 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2205 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2206
2207 assert_let!(
2208 Err(OlmError::SessionRecipientCollectionError(
2209 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2210 )) = withheld_code_for_device_for_share_strategy(
2211 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2212 CollectStrategy::ErrorOnVerifiedUserProblem,
2213 &own_identity_data,
2214 &own_user_identity_data,
2215 )
2216 .await
2217 );
2218
2219 own_identity.withdraw_verification().await.unwrap();
2221
2222 collect_session_recipients(
2223 machine.store(),
2224 iter::once(DataSet::own_id()),
2225 &encryption_settings,
2226 &group_session,
2227 )
2228 .await
2229 .unwrap();
2230
2231 #[cfg(feature = "experimental-send-custom-to-device")]
2232 {
2233 let all_devices: Vec<DeviceData> =
2234 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2235
2236 split_devices_for_share_strategy(
2237 machine.store(),
2238 all_devices,
2239 CollectStrategy::ErrorOnVerifiedUserProblem,
2240 )
2241 .await
2242 .unwrap();
2243 }
2244
2245 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2246 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2247
2248 withheld_code_for_device_for_share_strategy(
2249 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2250 CollectStrategy::ErrorOnVerifiedUserProblem,
2251 &own_identity_data,
2252 &own_user_identity_data,
2253 )
2254 .await
2255 .unwrap();
2256 }
2257
2258 mod dehydrated_device {
2261 use std::{collections::HashSet, iter};
2262
2263 use insta::{allow_duplicates, assert_json_snapshot, with_settings};
2264 use matrix_sdk_common::deserialized_responses::WithheldCode;
2265 use matrix_sdk_test::{
2266 async_test, ruma_response_to_json,
2267 test_json::keys_query_sets::{
2268 KeyDistributionTestData, KeyQueryResponseTemplate,
2269 KeyQueryResponseTemplateDeviceOptions,
2270 },
2271 };
2272 use ruma::{DeviceId, TransactionId, UserId, device_id, user_id};
2273 use vodozemac::{Curve25519PublicKey, Ed25519SecretKey};
2274
2275 use super::{
2276 all_devices_strategy_settings, create_test_outbound_group_session,
2277 error_on_verification_problem_encryption_settings, identity_based_strategy_settings,
2278 test_machine,
2279 };
2280 use crate::{
2281 EncryptionSettings, OlmMachine,
2282 session_manager::group_sessions::{
2283 CollectRecipientsResult, share_strategy::collect_session_recipients,
2284 },
2285 };
2286
2287 #[async_test]
2288 async fn test_all_devices_strategy_should_share_with_verified_dehydrated_device() {
2289 should_share_with_verified_dehydrated_device(&all_devices_strategy_settings()).await
2290 }
2291
2292 #[async_test]
2293 async fn test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device()
2294 {
2295 should_share_with_verified_dehydrated_device(
2296 &error_on_verification_problem_encryption_settings(),
2297 )
2298 .await
2299 }
2300
2301 #[async_test]
2302 async fn test_identity_based_strategy_should_share_with_verified_dehydrated_device() {
2303 should_share_with_verified_dehydrated_device(&identity_based_strategy_settings()).await
2304 }
2305
2306 async fn should_share_with_verified_dehydrated_device(
2311 encryption_settings: &EncryptionSettings,
2312 ) {
2313 let machine = test_machine().await;
2314
2315 let bob_user_id = user_id!("@bob:localhost");
2318 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2319 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2320 .with_dehydrated_device(bob_dehydrated_device_id, true)
2321 .build_response();
2322 allow_duplicates! {
2323 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2324 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2325 });
2326 }
2327 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2328
2329 let recips = share_test_session_and_collect_recipients(
2331 &machine,
2332 bob_user_id,
2333 encryption_settings,
2334 )
2335 .await;
2336
2337 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2339 }
2340
2341 #[async_test]
2342 async fn test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device() {
2343 should_not_share_with_unverified_dehydrated_device(&all_devices_strategy_settings())
2344 .await
2345 }
2346
2347 #[async_test]
2348 async fn test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device()
2349 {
2350 should_not_share_with_unverified_dehydrated_device(
2351 &error_on_verification_problem_encryption_settings(),
2352 )
2353 .await
2354 }
2355
2356 #[async_test]
2357 async fn test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device() {
2358 should_not_share_with_unverified_dehydrated_device(&identity_based_strategy_settings())
2359 .await
2360 }
2361
2362 async fn should_not_share_with_unverified_dehydrated_device(
2367 encryption_settings: &EncryptionSettings,
2368 ) {
2369 let machine = test_machine().await;
2370
2371 let bob_user_id = user_id!("@bob:localhost");
2374 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2375 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2376 .with_dehydrated_device(bob_dehydrated_device_id, false)
2377 .build_response();
2378 allow_duplicates! {
2379 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2380 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2381 });
2382 }
2383 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2384
2385 let recips = share_test_session_and_collect_recipients(
2387 &machine,
2388 bob_user_id,
2389 encryption_settings,
2390 )
2391 .await;
2392
2393 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2396 }
2397
2398 #[async_test]
2399 async fn test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user()
2400 {
2401 should_share_with_verified_device_of_pin_violation_user(
2402 &all_devices_strategy_settings(),
2403 )
2404 .await
2405 }
2406
2407 #[async_test]
2408 async fn test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user()
2409 {
2410 should_share_with_verified_device_of_pin_violation_user(
2411 &error_on_verification_problem_encryption_settings(),
2412 )
2413 .await
2414 }
2415
2416 #[async_test]
2417 async fn test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user()
2418 {
2419 should_share_with_verified_device_of_pin_violation_user(
2420 &identity_based_strategy_settings(),
2421 )
2422 .await
2423 }
2424
2425 async fn should_share_with_verified_device_of_pin_violation_user(
2430 encryption_settings: &EncryptionSettings,
2431 ) {
2432 let machine = test_machine().await;
2433
2434 let bob_user_id = user_id!("@bob:localhost");
2436 let keys_query =
2437 key_query_response_template_with_cross_signing(bob_user_id).build_response();
2438 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2439
2440 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2443 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2444 .with_dehydrated_device(bob_dehydrated_device_id, true)
2445 .build_response();
2446 allow_duplicates! {
2447 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2448 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2449 });
2450 }
2451 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2452
2453 let recips = share_test_session_and_collect_recipients(
2455 &machine,
2456 bob_user_id,
2457 encryption_settings,
2458 )
2459 .await;
2460
2461 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2463 }
2464
2465 #[async_test]
2466 async fn test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user()
2467 {
2468 should_not_share_with_dehydrated_device_of_verification_violation_user(
2469 &all_devices_strategy_settings(),
2470 )
2471 .await
2472 }
2473
2474 async fn should_not_share_with_dehydrated_device_of_verification_violation_user(
2477 encryption_settings: &EncryptionSettings,
2478 ) {
2479 let bob_user_id = user_id!("@bob:localhost");
2480 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2481 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2482 bob_user_id,
2483 bob_dehydrated_device_id,
2484 )
2485 .await;
2486
2487 let recips = share_test_session_and_collect_recipients(
2489 &machine,
2490 bob_user_id,
2491 encryption_settings,
2492 )
2493 .await;
2494
2495 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2498 }
2499
2500 #[async_test]
2501 async fn test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2502 {
2503 should_give_error_for_dehydrated_device_of_verification_violation_user(
2504 &error_on_verification_problem_encryption_settings(),
2505 )
2506 .await
2507 }
2508
2509 #[async_test]
2510 async fn test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2511 {
2512 should_give_error_for_dehydrated_device_of_verification_violation_user(
2516 &identity_based_strategy_settings(),
2517 )
2518 .await
2519 }
2520
2521 async fn should_give_error_for_dehydrated_device_of_verification_violation_user(
2525 encryption_settings: &EncryptionSettings,
2526 ) {
2527 let bob_user_id = user_id!("@bob:localhost");
2528 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2529 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2530 bob_user_id,
2531 bob_dehydrated_device_id,
2532 )
2533 .await;
2534
2535 let group_session = create_test_outbound_group_session(&machine, encryption_settings);
2536 let share_result = collect_session_recipients(
2537 machine.store(),
2538 iter::once(bob_user_id),
2539 encryption_settings,
2540 &group_session,
2541 )
2542 .await;
2543
2544 assert_matches::assert_matches!(
2547 share_result,
2548 Err(crate::OlmError::SessionRecipientCollectionError(
2549 crate::SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2550 ))
2551 );
2552 }
2553
2554 async fn prepare_machine_with_dehydrated_device_of_verification_violation_user(
2558 bob_user_id: &UserId,
2559 bob_dehydrated_device_id: &DeviceId,
2560 ) -> OlmMachine {
2561 let machine = test_machine().await;
2562
2563 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2565 .with_user_verification_signature(
2566 KeyDistributionTestData::me_id(),
2567 &KeyDistributionTestData::me_private_user_signing_key(),
2568 )
2569 .build_response();
2570 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2571
2572 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2575 .with_dehydrated_device(bob_dehydrated_device_id, true)
2576 .build_response();
2577 allow_duplicates! {
2578 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2579 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2580 });
2581 }
2582 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2583
2584 machine
2585 }
2586
2587 async fn share_test_session_and_collect_recipients(
2590 machine: &OlmMachine,
2591 target_user_id: &UserId,
2592 encryption_settings: &EncryptionSettings,
2593 ) -> CollectRecipientsResult {
2594 let group_session = create_test_outbound_group_session(machine, encryption_settings);
2595 collect_session_recipients(
2596 machine.store(),
2597 iter::once(target_user_id),
2598 encryption_settings,
2599 &group_session,
2600 )
2601 .await
2602 .unwrap()
2603 }
2604
2605 fn assert_shared_with(
2608 recips: CollectRecipientsResult,
2609 user_id: &UserId,
2610 device_ids: HashSet<&DeviceId>,
2611 ) {
2612 let bob_devices_shared: HashSet<_> = recips
2613 .devices
2614 .get(user_id)
2615 .unwrap_or_else(|| panic!("session not shared with {user_id}"))
2616 .iter()
2617 .map(|d| d.device_id())
2618 .collect();
2619 assert_eq!(bob_devices_shared, device_ids);
2620
2621 assert!(recips.withheld_devices.is_empty(), "Unexpected withheld messages");
2622 }
2623
2624 fn assert_withheld_to(
2627 recips: CollectRecipientsResult,
2628 bob_user_id: &UserId,
2629 bob_dehydrated_device_id: &DeviceId,
2630 ) {
2631 for (user, device_list) in recips.devices {
2633 assert_eq!(device_list.len(), 0, "session unexpectedly shared with {user}");
2634 }
2635
2636 assert_eq!(recips.withheld_devices.len(), 1);
2638 assert_eq!(recips.withheld_devices[0].0.user_id(), bob_user_id);
2639 assert_eq!(recips.withheld_devices[0].0.device_id(), bob_dehydrated_device_id);
2640 assert_eq!(recips.withheld_devices[0].1, WithheldCode::Unverified);
2641 }
2642
2643 fn key_query_response_template_with_cross_signing(
2646 user_id: &UserId,
2647 ) -> KeyQueryResponseTemplate {
2648 KeyQueryResponseTemplate::new(user_id.to_owned()).with_cross_signing_keys(
2649 Ed25519SecretKey::from_slice(b"master12master12master12master12"),
2650 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2651 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2652 )
2653 }
2654
2655 fn key_query_response_template_with_changed_cross_signing(
2659 bob_user_id: &UserId,
2660 ) -> KeyQueryResponseTemplate {
2661 KeyQueryResponseTemplate::new(bob_user_id.to_owned()).with_cross_signing_keys(
2662 Ed25519SecretKey::from_slice(b"newmaster__newmaster__newmaster_"),
2663 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2664 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2665 )
2666 }
2667
2668 trait KeyQueryResponseTemplateExt {
2669 fn with_dehydrated_device(
2670 self,
2671 device_id: &DeviceId,
2672 verified: bool,
2673 ) -> KeyQueryResponseTemplate;
2674 }
2675
2676 impl KeyQueryResponseTemplateExt for KeyQueryResponseTemplate {
2677 fn with_dehydrated_device(
2679 self,
2680 device_id: &DeviceId,
2681 verified: bool,
2682 ) -> KeyQueryResponseTemplate {
2683 self.with_device(
2684 device_id,
2685 &Curve25519PublicKey::from(b"curvepubcurvepubcurvepubcurvepub".to_owned()),
2686 &Ed25519SecretKey::from_slice(b"device12device12device12device12"),
2687 KeyQueryResponseTemplateDeviceOptions::new()
2688 .dehydrated(true)
2689 .verified(verified),
2690 )
2691 }
2692 }
2693 }
2694
2695 #[async_test]
2696 async fn test_share_with_identity_strategy() {
2697 let machine = test_machine().await;
2698 import_known_users_to_test_machine(&machine).await;
2699
2700 let encryption_settings = identity_based_strategy_settings();
2701
2702 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2703
2704 let share_result = collect_session_recipients(
2705 machine.store(),
2706 vec![
2707 KeyDistributionTestData::dan_id(),
2708 KeyDistributionTestData::dave_id(),
2709 KeyDistributionTestData::good_id(),
2710 ]
2711 .into_iter(),
2712 &encryption_settings,
2713 &group_session,
2714 )
2715 .await
2716 .unwrap();
2717
2718 assert!(!share_result.should_rotate);
2719
2720 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
2721 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
2722 assert!(dave_devices_shared.unwrap().is_empty());
2724
2725 assert_eq!(good_devices_shared.unwrap().len(), 2);
2727
2728 let dan_devices_shared =
2731 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
2732
2733 assert_eq!(dan_devices_shared.len(), 1);
2734 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
2735 assert_eq!(
2736 dan_device_that_will_get_the_key.device_id().as_str(),
2737 KeyDistributionTestData::dan_signed_device_id()
2738 );
2739
2740 let (_, code) = share_result
2742 .withheld_devices
2743 .iter()
2744 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
2745 .expect("This dan's device should receive a withheld code");
2746
2747 assert_eq!(code, &WithheldCode::Unverified);
2748
2749 let (_, code) = share_result
2751 .withheld_devices
2752 .iter()
2753 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
2754 .expect("This dave device should receive a withheld code");
2755
2756 assert_eq!(code, &WithheldCode::Unverified);
2757 }
2758
2759 #[async_test]
2762 async fn test_share_identity_strategy_no_cross_signing() {
2763 let machine: OlmMachine = OlmMachine::new(
2766 KeyDistributionTestData::me_id(),
2767 KeyDistributionTestData::me_device_id(),
2768 )
2769 .await;
2770
2771 let keys_query = KeyDistributionTestData::dan_keys_query_response();
2772 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2773
2774 let fake_room_id = room_id!("!roomid:localhost");
2775
2776 let encryption_settings = identity_based_strategy_settings();
2777
2778 let request_result = machine
2779 .share_room_key(
2780 fake_room_id,
2781 iter::once(KeyDistributionTestData::dan_id()),
2782 encryption_settings.clone(),
2783 )
2784 .await;
2785
2786 assert_matches!(
2787 request_result,
2788 Err(OlmError::SessionRecipientCollectionError(
2789 SessionRecipientCollectionError::CrossSigningNotSetup
2790 ))
2791 );
2792
2793 let keys_query = KeyDistributionTestData::me_keys_query_response();
2797 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2798
2799 let request_result = machine
2800 .share_room_key(
2801 fake_room_id,
2802 iter::once(KeyDistributionTestData::dan_id()),
2803 encryption_settings.clone(),
2804 )
2805 .await;
2806
2807 assert_matches!(
2808 request_result,
2809 Err(OlmError::SessionRecipientCollectionError(
2810 SessionRecipientCollectionError::SendingFromUnverifiedDevice
2811 ))
2812 );
2813
2814 machine
2817 .import_cross_signing_keys(CrossSigningKeyExport {
2818 master_key: KeyDistributionTestData::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
2819 self_signing_key: KeyDistributionTestData::SELF_SIGNING_KEY_PRIVATE_EXPORT
2820 .to_owned()
2821 .into(),
2822 user_signing_key: KeyDistributionTestData::USER_SIGNING_KEY_PRIVATE_EXPORT
2823 .to_owned()
2824 .into(),
2825 })
2826 .await
2827 .unwrap();
2828
2829 let requests = machine
2830 .share_room_key(
2831 fake_room_id,
2832 iter::once(KeyDistributionTestData::dan_id()),
2833 encryption_settings.clone(),
2834 )
2835 .await
2836 .unwrap();
2837
2838 assert_eq!(requests.len(), 1);
2841 }
2842
2843 #[async_test]
2847 async fn test_share_identity_strategy_report_verification_violation() {
2848 let machine: OlmMachine = OlmMachine::new(
2849 KeyDistributionTestData::me_id(),
2850 KeyDistributionTestData::me_device_id(),
2851 )
2852 .await;
2853
2854 machine.bootstrap_cross_signing(false).await.unwrap();
2855
2856 let user1 = IdentityChangeDataSet::user_id();
2858 let user2 = MaloIdentityChangeDataSet::user_id();
2859
2860 let keys_query = IdentityChangeDataSet::key_query_with_identity_a();
2862 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2863
2864 let keys_query = MaloIdentityChangeDataSet::initial_key_query();
2865 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2866
2867 let keys_query = IdentityChangeDataSet::key_query_with_identity_b();
2871 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2872 machine
2873 .get_identity(user1, None)
2874 .await
2875 .unwrap()
2876 .unwrap()
2877 .other()
2878 .unwrap()
2879 .mark_as_previously_verified()
2880 .await
2881 .unwrap();
2882
2883 let keys_query = MaloIdentityChangeDataSet::updated_key_query();
2884 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2885 machine
2886 .get_identity(user2, None)
2887 .await
2888 .unwrap()
2889 .unwrap()
2890 .other()
2891 .unwrap()
2892 .mark_as_previously_verified()
2893 .await
2894 .unwrap();
2895
2896 let fake_room_id = room_id!("!roomid:localhost");
2897
2898 let encryption_settings = identity_based_strategy_settings();
2900
2901 let request_result = machine
2902 .share_room_key(
2903 fake_room_id,
2904 vec![user1, user2].into_iter(),
2905 encryption_settings.clone(),
2906 )
2907 .await;
2908
2909 assert_let!(
2912 Err(OlmError::SessionRecipientCollectionError(
2913 SessionRecipientCollectionError::VerifiedUserChangedIdentity(affected_users)
2914 )) = request_result
2915 );
2916 assert_eq!(2, affected_users.len());
2918
2919 machine
2921 .get_identity(user1, None)
2922 .await
2923 .unwrap()
2924 .unwrap()
2925 .withdraw_verification()
2926 .await
2927 .unwrap();
2928
2929 let verification_request = machine
2931 .get_identity(user2, None)
2932 .await
2933 .unwrap()
2934 .unwrap()
2935 .other()
2936 .unwrap()
2937 .verify()
2938 .await
2939 .unwrap();
2940
2941 let master_key =
2942 &machine.get_identity(user2, None).await.unwrap().unwrap().other().unwrap().master_key;
2943
2944 let my_identity = machine
2945 .get_identity(KeyDistributionTestData::me_id(), None)
2946 .await
2947 .expect("Should not fail to find own identity")
2948 .expect("Our own identity should not be missing")
2949 .own()
2950 .expect("Our own identity should be of type Own");
2951
2952 let msk = json!({ user2: serde_json::to_value(master_key).expect("Should not fail to serialize")});
2953 let ssk =
2954 serde_json::to_value(&MaloIdentityChangeDataSet::updated_key_query().self_signing_keys)
2955 .expect("Should not fail to serialize");
2956
2957 let kq_response = simulate_key_query_response_for_verification(
2958 verification_request,
2959 my_identity,
2960 KeyDistributionTestData::me_id(),
2961 user2,
2962 msk,
2963 ssk,
2964 );
2965
2966 machine
2967 .mark_request_as_sent(
2968 &TransactionId::new(),
2969 crate::types::requests::AnyIncomingResponse::KeysQuery(&kq_response),
2970 )
2971 .await
2972 .unwrap();
2973
2974 assert!(machine.get_identity(user2, None).await.unwrap().unwrap().is_verified());
2975
2976 machine
2978 .share_room_key(
2979 fake_room_id,
2980 vec![user1, user2].into_iter(),
2981 encryption_settings.clone(),
2982 )
2983 .await
2984 .unwrap();
2985 }
2986
2987 #[async_test]
2988 async fn test_should_rotate_based_on_visibility() {
2989 let machine = test_machine().await;
2990 import_known_users_to_test_machine(&machine).await;
2991
2992 let strategy = CollectStrategy::AllDevices;
2993
2994 let encryption_settings = EncryptionSettings {
2995 sharing_strategy: strategy.clone(),
2996 history_visibility: HistoryVisibility::Invited,
2997 ..Default::default()
2998 };
2999
3000 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3001
3002 let _ = collect_session_recipients(
3003 machine.store(),
3004 vec![KeyDistributionTestData::dan_id()].into_iter(),
3005 &encryption_settings,
3006 &group_session,
3007 )
3008 .await
3009 .unwrap();
3010
3011 let encryption_settings = EncryptionSettings {
3013 sharing_strategy: strategy.clone(),
3014 history_visibility: HistoryVisibility::Shared,
3015 ..Default::default()
3016 };
3017
3018 let share_result = collect_session_recipients(
3019 machine.store(),
3020 vec![KeyDistributionTestData::dan_id()].into_iter(),
3021 &encryption_settings,
3022 &group_session,
3023 )
3024 .await
3025 .unwrap();
3026
3027 assert!(share_result.should_rotate);
3028 }
3029
3030 #[async_test]
3034 async fn test_should_rotate_based_on_device_excluded() {
3035 let machine = test_machine().await;
3036 import_known_users_to_test_machine(&machine).await;
3037
3038 let encryption_settings = all_devices_strategy_settings();
3039 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3040 let sender_key = machine.identity_keys().curve25519;
3041
3042 group_session
3043 .mark_shared_with(
3044 KeyDistributionTestData::dan_id(),
3045 KeyDistributionTestData::dan_signed_device_id(),
3046 sender_key,
3047 )
3048 .await;
3049 group_session
3050 .mark_shared_with(
3051 KeyDistributionTestData::dan_id(),
3052 KeyDistributionTestData::dan_unsigned_device_id(),
3053 sender_key,
3054 )
3055 .await;
3056
3057 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3059 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3060
3061 let share_result = collect_session_recipients(
3063 machine.store(),
3064 vec![KeyDistributionTestData::dan_id()].into_iter(),
3065 &encryption_settings,
3066 &group_session,
3067 )
3068 .await
3069 .unwrap();
3070
3071 assert!(share_result.should_rotate);
3072 }
3073
3074 #[async_test]
3077 async fn test_should_rotate_based_on_device_with_pending_request_excluded() {
3078 let machine = test_machine().await;
3079 import_known_users_to_test_machine(&machine).await;
3080
3081 let encryption_settings = all_devices_strategy_settings();
3082 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3083 let sender_key = machine.identity_keys().curve25519;
3084
3085 let dan_user = KeyDistributionTestData::dan_id();
3086 let dan_dev1 = KeyDistributionTestData::dan_signed_device_id();
3087 let dan_dev2 = KeyDistributionTestData::dan_unsigned_device_id();
3088
3089 group_session.mark_shared_with(dan_user, dan_dev1, sender_key).await;
3091
3092 {
3093 let share_infos = BTreeMap::from([(
3095 dan_user.to_owned(),
3096 BTreeMap::from([(
3097 dan_dev2.to_owned(),
3098 ShareInfo::new_shared(sender_key, 0, SequenceNumber::default()),
3099 )]),
3100 )]);
3101
3102 let txid = TransactionId::new();
3103 let req = Arc::new(ToDeviceRequest::for_recipients(
3104 dan_user,
3105 vec![dan_dev2.to_owned()],
3106 &ruma::events::AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent),
3107 txid.clone(),
3108 ));
3109 group_session.add_request(txid, req, share_infos);
3110 }
3111
3112 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3114 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3115
3116 let share_result = collect_session_recipients(
3118 machine.store(),
3119 vec![KeyDistributionTestData::dan_id()].into_iter(),
3120 &encryption_settings,
3121 &group_session,
3122 )
3123 .await
3124 .unwrap();
3125
3126 assert!(share_result.should_rotate);
3127 }
3128
3129 #[async_test]
3132 async fn test_should_not_rotate_if_keys_were_withheld() {
3133 let machine = test_machine().await;
3134 import_known_users_to_test_machine(&machine).await;
3135
3136 let encryption_settings = all_devices_strategy_settings();
3137 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3138 let fake_room_id = group_session.room_id();
3139
3140 let requests = machine
3143 .share_room_key(
3144 fake_room_id,
3145 vec![KeyDistributionTestData::dan_id()].into_iter(),
3146 encryption_settings.clone(),
3147 )
3148 .await
3149 .unwrap();
3150
3151 for r in requests {
3152 machine
3153 .inner
3154 .group_session_manager
3155 .mark_request_as_sent(r.as_ref().txn_id.as_ref())
3156 .await
3157 .unwrap();
3158 }
3159
3160 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3162 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3163
3164 let share_result = collect_session_recipients(
3166 machine.store(),
3167 vec![KeyDistributionTestData::dan_id()].into_iter(),
3168 &encryption_settings,
3169 &group_session,
3170 )
3171 .await
3172 .unwrap();
3173
3174 assert!(!share_result.should_rotate);
3175 }
3176
3177 async fn unsigned_of_verified_setup() -> OlmMachine {
3185 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
3186
3187 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
3188
3189 let own_keys = DataSet::own_keys_query_response_1();
3191 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
3192
3193 machine
3195 .import_cross_signing_keys(CrossSigningKeyExport {
3196 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
3197 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3198 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3199 })
3200 .await
3201 .unwrap();
3202
3203 let bob_keys = DataSet::bob_keys_query_response_signed();
3205 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
3206
3207 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
3210 assert!(bob_identity.other().unwrap().is_verified());
3211
3212 let bob_signed_device = machine
3213 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
3214 .await
3215 .unwrap()
3216 .unwrap();
3217 assert!(bob_signed_device.is_verified());
3218 assert!(bob_signed_device.device_owner_identity.is_some());
3219
3220 let bob_unsigned_device = machine
3221 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
3222 .await
3223 .unwrap()
3224 .unwrap();
3225 assert!(!bob_unsigned_device.is_verified());
3226
3227 machine
3228 }
3229
3230 fn all_devices_strategy_settings() -> EncryptionSettings {
3232 EncryptionSettings { sharing_strategy: CollectStrategy::AllDevices, ..Default::default() }
3233 }
3234
3235 fn error_on_verification_problem_encryption_settings() -> EncryptionSettings {
3238 EncryptionSettings {
3239 sharing_strategy: CollectStrategy::ErrorOnVerifiedUserProblem,
3240 ..Default::default()
3241 }
3242 }
3243
3244 fn identity_based_strategy_settings() -> EncryptionSettings {
3246 EncryptionSettings {
3247 sharing_strategy: CollectStrategy::IdentityBasedStrategy,
3248 ..Default::default()
3249 }
3250 }
3251
3252 fn create_test_outbound_group_session(
3255 machine: &OlmMachine,
3256 encryption_settings: &EncryptionSettings,
3257 ) -> OutboundGroupSession {
3258 OutboundGroupSession::new(
3259 machine.device_id().into(),
3260 Arc::new(machine.identity_keys()),
3261 room_id!("!roomid:localhost"),
3262 encryption_settings.clone(),
3263 )
3264 .expect("creating an outbound group session should not fail")
3265 }
3266}