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