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 blocked_devices.push((device.clone(), WithheldCode::Unverified));
622 }
623 }
624 }
625
626 CollectStrategy::OnlyTrustedDevices => {
627 for device in devices.iter() {
628 let user_id = device.user_id();
629 let device_owner_identity = get_user_identity(user_id).await?;
630
631 if let Some(withheld_code) =
632 withheld_code_for_device_for_only_trusted_devices_strategy(
633 device,
634 &own_identity,
635 &device_owner_identity,
636 )
637 {
638 blocked_devices.push((device.clone(), withheld_code));
639 } else {
640 allowed_devices.push(device.clone());
641 }
642 }
643 }
644 }
645
646 if !verified_users_with_new_identities.is_empty() {
647 return Err(OlmError::SessionRecipientCollectionError(
648 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
649 verified_users_with_new_identities.into_iter().collect(),
650 ),
651 ));
652 }
653
654 Ok((allowed_devices, blocked_devices))
655}
656
657pub(crate) async fn withheld_code_for_device_for_share_strategy(
658 device: &DeviceData,
659 share_strategy: CollectStrategy,
660 own_identity: &Option<OwnUserIdentityData>,
661 device_owner_identity: &Option<UserIdentityData>,
662) -> OlmResult<Option<WithheldCode>> {
663 match share_strategy {
664 CollectStrategy::AllDevices => Ok(withheld_code_for_device_for_all_devices_strategy(
665 device,
666 own_identity,
667 device_owner_identity,
668 )),
669 CollectStrategy::ErrorOnVerifiedUserProblem => {
670 if has_identity_verification_violation(
671 own_identity.as_ref(),
672 device_owner_identity.as_ref(),
673 ) {
674 return Err(OlmError::SessionRecipientCollectionError(
675 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
676 device.user_id().to_owned(),
677 ]),
678 ));
679 }
680 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
681 device,
682 own_identity.as_ref(),
683 device_owner_identity.as_ref(),
684 ) {
685 ErrorOnVerifiedUserProblemDeviceDecision::Ok => Ok(None),
686 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => Ok(Some(code)),
687 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
688 Err(OlmError::SessionRecipientCollectionError(
689 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
690 BTreeMap::from([(
691 device.user_id().to_owned(),
692 vec![device.device_id().to_owned()],
693 )]),
694 ),
695 ))
696 }
697 }
698 }
699 CollectStrategy::IdentityBasedStrategy => {
700 match &own_identity {
703 None => {
704 return Err(OlmError::SessionRecipientCollectionError(
705 SessionRecipientCollectionError::CrossSigningNotSetup,
706 ));
707 }
708 Some(identity) if !identity.is_verified() => {
709 return Err(OlmError::SessionRecipientCollectionError(
710 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
711 ));
712 }
713 Some(_) => (),
714 }
715
716 if has_identity_verification_violation(
717 own_identity.as_ref(),
718 device_owner_identity.as_ref(),
719 ) {
720 Err(OlmError::SessionRecipientCollectionError(
721 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
722 device.user_id().to_owned(),
723 ]),
724 ))
725 } else if let Some(device_owner_identity) = device_owner_identity {
726 Ok(withheld_code_for_device_with_owner_for_identity_based_strategy(
727 device,
728 device_owner_identity,
729 ))
730 } else {
731 Ok(Some(WithheldCode::Unverified))
734 }
735 }
736 CollectStrategy::OnlyTrustedDevices => {
737 Ok(withheld_code_for_device_for_only_trusted_devices_strategy(
738 device,
739 own_identity,
740 device_owner_identity,
741 ))
742 }
743 }
744}
745
746#[derive(Default)]
753struct RecipientDevicesForUser {
754 allowed_devices: Vec<DeviceData>,
756 denied_devices_with_code: Vec<(DeviceData, WithheldCode)>,
758}
759
760enum ErrorOnVerifiedUserProblemResult {
763 UnsignedDevicesOfVerifiedUser(Vec<OwnedDeviceId>),
767
768 Devices(RecipientDevicesForUser),
770}
771
772fn split_devices_for_user_for_all_devices_strategy(
775 user_devices: HashMap<OwnedDeviceId, DeviceData>,
776 own_identity: &Option<OwnUserIdentityData>,
777 device_owner_identity: &Option<UserIdentityData>,
778) -> RecipientDevicesForUser {
779 let (left, right) = user_devices.into_values().partition_map(|d| {
780 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
781 &d,
782 own_identity,
783 device_owner_identity,
784 ) {
785 Either::Right((d, withheld_code))
786 } else {
787 Either::Left(d)
788 }
789 });
790
791 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
792}
793
794fn withheld_code_for_device_for_all_devices_strategy(
798 device_data: &DeviceData,
799 own_identity: &Option<OwnUserIdentityData>,
800 device_owner_identity: &Option<UserIdentityData>,
801) -> Option<WithheldCode> {
802 if device_data.is_blacklisted() {
803 Some(WithheldCode::Blacklisted)
804 } else if device_data.is_dehydrated()
805 && should_withhold_to_dehydrated_device(
806 device_data,
807 own_identity.as_ref(),
808 device_owner_identity.as_ref(),
809 )
810 {
811 Some(WithheldCode::Unverified)
812 } else {
813 None
814 }
815}
816
817fn should_withhold_to_dehydrated_device(
826 device: &DeviceData,
827 own_identity: Option<&OwnUserIdentityData>,
828 device_owner_identity: Option<&UserIdentityData>,
829) -> bool {
830 device_owner_identity.is_none_or(|owner_id| {
831 !device.is_cross_signed_by_owner(owner_id) ||
833
834 (owner_id.was_previously_verified() && !is_user_verified(own_identity, owner_id))
836 })
837}
838
839fn split_devices_for_user_for_error_on_verified_user_problem_strategy(
852 user_devices: HashMap<OwnedDeviceId, DeviceData>,
853 own_identity: &Option<OwnUserIdentityData>,
854 device_owner_identity: &Option<UserIdentityData>,
855) -> ErrorOnVerifiedUserProblemResult {
856 let mut recipient_devices = RecipientDevicesForUser::default();
857
858 let mut unsigned_devices_of_verified_users: Option<Vec<OwnedDeviceId>> = None;
861
862 for d in user_devices.into_values() {
863 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
864 &d,
865 own_identity.as_ref(),
866 device_owner_identity.as_ref(),
867 ) {
868 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
869 recipient_devices.allowed_devices.push(d)
870 }
871 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
872 recipient_devices.denied_devices_with_code.push((d, code))
873 }
874 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
875 unsigned_devices_of_verified_users
876 .get_or_insert_with(Vec::default)
877 .push(d.device_id().to_owned())
878 }
879 }
880 }
881
882 if let Some(devices) = unsigned_devices_of_verified_users {
883 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices)
884 } else {
885 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices)
886 }
887}
888
889enum ErrorOnVerifiedUserProblemDeviceDecision {
892 Ok,
893 Withhold(WithheldCode),
894 UnsignedOfVerified,
895}
896
897fn handle_device_for_user_for_error_on_verified_user_problem_strategy(
898 device: &DeviceData,
899 own_identity: Option<&OwnUserIdentityData>,
900 device_owner_identity: Option<&UserIdentityData>,
901) -> ErrorOnVerifiedUserProblemDeviceDecision {
902 if device.is_blacklisted() {
903 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Blacklisted)
904 } else if device.local_trust_state() == LocalTrust::Ignored {
905 ErrorOnVerifiedUserProblemDeviceDecision::Ok
907 } else if is_unsigned_device_of_verified_user(own_identity, device_owner_identity, device) {
908 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified
909 } else if device.is_dehydrated()
910 && device_owner_identity.is_none_or(|owner_id| {
911 !device.is_cross_signed_by_owner(owner_id)
914 })
915 {
916 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Unverified)
917 } else {
918 ErrorOnVerifiedUserProblemDeviceDecision::Ok
919 }
920}
921
922fn split_devices_for_user_for_identity_based_strategy(
923 user_devices: HashMap<OwnedDeviceId, DeviceData>,
924 device_owner_identity: &Option<UserIdentityData>,
925) -> RecipientDevicesForUser {
926 match device_owner_identity {
927 None => {
928 RecipientDevicesForUser {
931 allowed_devices: Vec::default(),
932 denied_devices_with_code: user_devices
933 .into_values()
934 .map(|d| (d, WithheldCode::Unverified))
935 .collect(),
936 }
937 }
938 Some(device_owner_identity) => {
939 let (recipients, withheld_recipients): (
941 Vec<DeviceData>,
942 Vec<(DeviceData, WithheldCode)>,
943 ) = user_devices.into_values().partition_map(|d| {
944 if let Some(withheld_code) =
945 withheld_code_for_device_with_owner_for_identity_based_strategy(
946 &d,
947 device_owner_identity,
948 )
949 {
950 Either::Right((d, withheld_code))
951 } else {
952 Either::Left(d)
953 }
954 });
955 RecipientDevicesForUser {
956 allowed_devices: recipients,
957 denied_devices_with_code: withheld_recipients,
958 }
959 }
960 }
961}
962
963fn withheld_code_for_device_with_owner_for_identity_based_strategy(
967 device_data: &DeviceData,
968 device_owner_identity: &UserIdentityData,
969) -> Option<WithheldCode> {
970 if device_data.is_cross_signed_by_owner(device_owner_identity) {
971 None
972 } else {
973 Some(WithheldCode::Unverified)
974 }
975}
976
977fn split_devices_for_user_for_only_trusted_devices(
980 user_devices: HashMap<OwnedDeviceId, DeviceData>,
981 own_identity: &Option<OwnUserIdentityData>,
982 device_owner_identity: &Option<UserIdentityData>,
983) -> RecipientDevicesForUser {
984 let (left, right) = user_devices.into_values().partition_map(|d| {
985 if let Some(withheld_code) = withheld_code_for_device_for_only_trusted_devices_strategy(
986 &d,
987 own_identity,
988 device_owner_identity,
989 ) {
990 Either::Right((d, withheld_code))
991 } else {
992 Either::Left(d)
993 }
994 });
995 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
996}
997
998fn withheld_code_for_device_for_only_trusted_devices_strategy(
1002 device_data: &DeviceData,
1003 own_identity: &Option<OwnUserIdentityData>,
1004 device_owner_identity: &Option<UserIdentityData>,
1005) -> Option<WithheldCode> {
1006 match (
1007 device_data.local_trust_state(),
1008 device_data.is_cross_signing_trusted(own_identity, device_owner_identity),
1009 ) {
1010 (LocalTrust::BlackListed, _) => Some(WithheldCode::Blacklisted),
1011 (LocalTrust::Ignored | LocalTrust::Verified, _) => None,
1012 (LocalTrust::Unset, false) => Some(WithheldCode::Unverified),
1013 (LocalTrust::Unset, true) => None,
1014 }
1015}
1016
1017fn is_unsigned_device_of_verified_user(
1018 own_identity: Option<&OwnUserIdentityData>,
1019 device_owner_identity: Option<&UserIdentityData>,
1020 device_data: &DeviceData,
1021) -> bool {
1022 device_owner_identity.is_some_and(|device_owner_identity| {
1023 is_user_verified(own_identity, device_owner_identity)
1024 && !device_data.is_cross_signed_by_owner(device_owner_identity)
1025 })
1026}
1027
1028fn has_identity_verification_violation(
1035 own_identity: Option<&OwnUserIdentityData>,
1036 device_owner_identity: Option<&UserIdentityData>,
1037) -> bool {
1038 device_owner_identity.is_some_and(|device_owner_identity| {
1039 device_owner_identity.was_previously_verified()
1040 && !is_user_verified(own_identity, device_owner_identity)
1041 })
1042}
1043
1044fn is_user_verified(
1045 own_identity: Option<&OwnUserIdentityData>,
1046 user_identity: &UserIdentityData,
1047) -> bool {
1048 match user_identity {
1049 UserIdentityData::Own(own_identity) => own_identity.is_verified(),
1050 UserIdentityData::Other(other_identity) => {
1051 own_identity.is_some_and(|oi| oi.is_identity_verified(other_identity))
1052 }
1053 }
1054}
1055
1056#[cfg(test)]
1057mod tests {
1058 use std::{collections::BTreeMap, iter, ops::Deref, sync::Arc};
1059
1060 use assert_matches::assert_matches;
1061 use assert_matches2::assert_let;
1062 use insta::{assert_snapshot, with_settings};
1063 use matrix_sdk_common::deserialized_responses::WithheldCode;
1064 use matrix_sdk_test::{
1065 async_test, test_json,
1066 test_json::keys_query_sets::{
1067 IdentityChangeDataSet, KeyDistributionTestData, MaloIdentityChangeDataSet,
1068 VerificationViolationTestData,
1069 },
1070 };
1071 use ruma::{
1072 DeviceId, TransactionId, UserId, device_id,
1073 events::{dummy::ToDeviceDummyEventContent, room::history_visibility::HistoryVisibility},
1074 room_id,
1075 };
1076 use serde_json::json;
1077
1078 #[cfg(feature = "experimental-send-custom-to-device")]
1079 use super::split_devices_for_share_strategy;
1080 use crate::{
1081 CrossSigningKeyExport, DeviceData, EncryptionSettings, LocalTrust, OlmError, OlmMachine,
1082 error::SessionRecipientCollectionError,
1083 olm::{OutboundGroupSession, ShareInfo},
1084 session_manager::{
1085 CollectStrategy,
1086 group_sessions::share_strategy::{
1087 collect_session_recipients, withheld_code_for_device_for_share_strategy,
1088 },
1089 },
1090 store::caches::SequenceNumber,
1091 testing::simulate_key_query_response_for_verification,
1092 types::requests::ToDeviceRequest,
1093 };
1094
1095 async fn test_machine() -> OlmMachine {
1099 use KeyDistributionTestData as DataSet;
1100
1101 let machine = OlmMachine::new(DataSet::me_id(), DataSet::me_device_id()).await;
1103 let keys_query = DataSet::me_keys_query_response();
1104 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1105
1106 machine
1108 .import_cross_signing_keys(CrossSigningKeyExport {
1109 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1110 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1111 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1112 })
1113 .await
1114 .unwrap();
1115
1116 machine
1117 }
1118
1119 async fn get_device_data(
1121 machine: &OlmMachine,
1122 user_id: &UserId,
1123 device_id: &DeviceId,
1124 ) -> DeviceData {
1125 machine.get_device(user_id, device_id, None).await.unwrap().unwrap().deref().clone()
1126 }
1127
1128 async fn get_own_identity_data(
1129 machine: &OlmMachine,
1130 user_id: &UserId,
1131 ) -> Option<crate::OwnUserIdentityData> {
1132 machine
1133 .get_identity(user_id, None)
1134 .await
1135 .unwrap()
1136 .and_then(|i| i.own())
1137 .map(|i| i.deref().clone())
1138 }
1139
1140 async fn get_user_identity_data(
1141 machine: &OlmMachine,
1142 user_id: &UserId,
1143 ) -> Option<crate::UserIdentityData> {
1144 use crate::{UserIdentity, identities::user::UserIdentityData};
1145 machine.get_identity(user_id, None).await.unwrap().map(|i| match i {
1146 UserIdentity::Own(i) => UserIdentityData::Own(i.deref().clone()),
1147 UserIdentity::Other(i) => UserIdentityData::Other(i.deref().clone()),
1148 })
1149 }
1150
1151 async fn import_known_users_to_test_machine(machine: &OlmMachine) {
1154 let keys_query = KeyDistributionTestData::dan_keys_query_response();
1155 let txn_id = TransactionId::new();
1156 machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap();
1157
1158 let txn_id_dave = TransactionId::new();
1159 let keys_query_dave = KeyDistributionTestData::dave_keys_query_response();
1160 machine.mark_request_as_sent(&txn_id_dave, &keys_query_dave).await.unwrap();
1161
1162 let txn_id_good = TransactionId::new();
1163 let keys_query_good = KeyDistributionTestData::good_keys_query_response();
1164 machine.mark_request_as_sent(&txn_id_good, &keys_query_good).await.unwrap();
1165 }
1166
1167 #[test]
1170 #[cfg(not(feature = "experimental-encrypted-state-events"))]
1171 fn test_serialize_device_based_strategy() {
1172 let encryption_settings = all_devices_strategy_settings();
1173 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1174 with_settings!({prepend_module_to_snapshot => false}, {
1175 assert_snapshot!(serialized)
1176 });
1177 }
1178
1179 #[test]
1183 #[cfg(feature = "experimental-encrypted-state-events")]
1184 fn test_serialize_strategy_with_encrypted_state() {
1185 let encryption_settings = all_devices_strategy_settings();
1186 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1187 with_settings!({prepend_module_to_snapshot => false}, {
1188 assert_snapshot!(serialized)
1189 });
1190 }
1191
1192 #[test]
1196 fn test_deserialize_old_device_based_strategy() {
1197 let settings: EncryptionSettings = serde_json::from_value(json!({
1198 "algorithm": "m.megolm.v1.aes-sha2",
1199 "rotation_period":{"secs":604800,"nanos":0},
1200 "rotation_period_msgs":100,
1201 "history_visibility":"shared",
1202 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":false}},
1203 })).unwrap();
1204 assert_matches!(settings.sharing_strategy, CollectStrategy::AllDevices);
1205 }
1206
1207 #[test]
1211 fn test_deserialize_old_error_on_verified_user_problem() {
1212 let settings: EncryptionSettings = serde_json::from_value(json!({
1213 "algorithm": "m.megolm.v1.aes-sha2",
1214 "rotation_period":{"secs":604800,"nanos":0},
1215 "rotation_period_msgs":100,
1216 "history_visibility":"shared",
1217 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":true}},
1218 })).unwrap();
1219 assert_matches!(settings.sharing_strategy, CollectStrategy::ErrorOnVerifiedUserProblem);
1220 }
1221
1222 #[test]
1226 fn test_deserialize_old_only_trusted_devices_strategy() {
1227 let settings: EncryptionSettings = serde_json::from_value(json!({
1228 "algorithm": "m.megolm.v1.aes-sha2",
1229 "rotation_period":{"secs":604800,"nanos":0},
1230 "rotation_period_msgs":100,
1231 "history_visibility":"shared",
1232 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":true,"error_on_verified_user_problem":false}},
1233 })).unwrap();
1234 assert_matches!(settings.sharing_strategy, CollectStrategy::OnlyTrustedDevices);
1235 }
1236
1237 #[async_test]
1238 async fn test_share_with_per_device_strategy_to_all() {
1239 let machine = test_machine().await;
1240 import_known_users_to_test_machine(&machine).await;
1241
1242 let encryption_settings = all_devices_strategy_settings();
1243
1244 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1245
1246 let share_result = collect_session_recipients(
1247 machine.store(),
1248 vec![
1249 KeyDistributionTestData::dan_id(),
1250 KeyDistributionTestData::dave_id(),
1251 KeyDistributionTestData::good_id(),
1252 ]
1253 .into_iter(),
1254 &encryption_settings,
1255 &group_session,
1256 )
1257 .await
1258 .unwrap();
1259
1260 assert!(!share_result.should_rotate);
1261
1262 let dan_devices_shared =
1263 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1264 let dave_devices_shared =
1265 share_result.devices.get(KeyDistributionTestData::dave_id()).unwrap();
1266 let good_devices_shared =
1267 share_result.devices.get(KeyDistributionTestData::good_id()).unwrap();
1268
1269 assert_eq!(dan_devices_shared.len(), 2);
1271 assert_eq!(dave_devices_shared.len(), 1);
1272 assert_eq!(good_devices_shared.len(), 2);
1273
1274 #[cfg(feature = "experimental-send-custom-to-device")]
1275 {
1276 let mut all_devices = dan_devices_shared.clone();
1280 all_devices.append(&mut dave_devices_shared.clone());
1281 all_devices.append(&mut good_devices_shared.clone());
1282
1283 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1284 machine.store(),
1285 all_devices,
1286 CollectStrategy::AllDevices,
1287 )
1288 .await
1289 .unwrap();
1290
1291 assert_eq!(shared_devices.len(), 5);
1292 assert_eq!(withheld_devices.len(), 0);
1293 }
1294
1295 let own_identity_data =
1296 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1297 let dan_identity_data =
1298 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1299
1300 assert_eq!(
1301 withheld_code_for_device_for_share_strategy(
1302 &get_device_data(
1303 &machine,
1304 KeyDistributionTestData::dan_id(),
1305 KeyDistributionTestData::dan_signed_device_id()
1306 )
1307 .await,
1308 CollectStrategy::AllDevices,
1309 &own_identity_data,
1310 &dan_identity_data,
1311 )
1312 .await
1313 .unwrap(),
1314 None,
1315 );
1316 }
1317
1318 #[async_test]
1319 async fn test_share_with_only_trusted_strategy() {
1320 let machine = test_machine().await;
1321 import_known_users_to_test_machine(&machine).await;
1322
1323 let encryption_settings = EncryptionSettings {
1324 sharing_strategy: CollectStrategy::OnlyTrustedDevices,
1325 ..Default::default()
1326 };
1327
1328 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1329
1330 let share_result = collect_session_recipients(
1331 machine.store(),
1332 vec![
1333 KeyDistributionTestData::dan_id(),
1334 KeyDistributionTestData::dave_id(),
1335 KeyDistributionTestData::good_id(),
1336 ]
1337 .into_iter(),
1338 &encryption_settings,
1339 &group_session,
1340 )
1341 .await
1342 .unwrap();
1343
1344 assert!(!share_result.should_rotate);
1345
1346 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
1347 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
1348 assert!(dave_devices_shared.unwrap().is_empty());
1350 assert!(good_devices_shared.unwrap().is_empty());
1351
1352 let dan_devices_shared =
1355 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1356
1357 assert_eq!(dan_devices_shared.len(), 1);
1358 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
1359 assert_eq!(
1360 dan_device_that_will_get_the_key.device_id().as_str(),
1361 KeyDistributionTestData::dan_signed_device_id()
1362 );
1363
1364 let (_, code) = share_result
1366 .withheld_devices
1367 .iter()
1368 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
1369 .expect("This dan's device should receive a withheld code");
1370
1371 assert_eq!(code, &WithheldCode::Unverified);
1372
1373 let (_, code) = share_result
1374 .withheld_devices
1375 .iter()
1376 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
1377 .expect("This daves's device should receive a withheld code");
1378
1379 assert_eq!(code, &WithheldCode::Unverified);
1380
1381 #[cfg(feature = "experimental-send-custom-to-device")]
1382 {
1383 let all_devices: Vec<DeviceData> = vec![
1384 get_device_data(
1385 &machine,
1386 KeyDistributionTestData::dan_id(),
1387 KeyDistributionTestData::dan_unsigned_device_id(),
1388 )
1389 .await,
1390 get_device_data(
1391 &machine,
1392 KeyDistributionTestData::dan_id(),
1393 KeyDistributionTestData::dan_signed_device_id(),
1394 )
1395 .await,
1396 get_device_data(
1397 &machine,
1398 KeyDistributionTestData::dave_id(),
1399 KeyDistributionTestData::dave_device_id(),
1400 )
1401 .await,
1402 get_device_data(
1403 &machine,
1404 KeyDistributionTestData::good_id(),
1405 KeyDistributionTestData::good_device_1_id(),
1406 )
1407 .await,
1408 get_device_data(
1409 &machine,
1410 KeyDistributionTestData::good_id(),
1411 KeyDistributionTestData::good_device_2_id(),
1412 )
1413 .await,
1414 ];
1415
1416 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1417 machine.store(),
1418 all_devices,
1419 CollectStrategy::OnlyTrustedDevices,
1420 )
1421 .await
1422 .unwrap();
1423
1424 assert_eq!(shared_devices.len(), 1);
1425 assert_eq!(
1426 shared_devices[0].device_id().as_str(),
1427 KeyDistributionTestData::dan_signed_device_id()
1428 );
1429
1430 assert_eq!(withheld_devices.len(), 4);
1431 assert_eq!(
1432 withheld_devices[0].0.device_id().as_str(),
1433 KeyDistributionTestData::dan_unsigned_device_id()
1434 );
1435 assert_eq!(withheld_devices[0].1, WithheldCode::Unverified);
1436 assert_eq!(
1437 withheld_devices[1].0.device_id().as_str(),
1438 KeyDistributionTestData::dave_device_id()
1439 );
1440 assert_eq!(withheld_devices[1].1, WithheldCode::Unverified);
1441 }
1442
1443 let own_identity_data =
1444 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1445 let dan_identity_data =
1446 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1447 let dave_identity_data =
1448 get_user_identity_data(&machine, KeyDistributionTestData::dave_id()).await;
1449
1450 assert_eq!(
1451 withheld_code_for_device_for_share_strategy(
1452 &get_device_data(
1453 &machine,
1454 KeyDistributionTestData::dan_id(),
1455 KeyDistributionTestData::dan_signed_device_id()
1456 )
1457 .await,
1458 CollectStrategy::OnlyTrustedDevices,
1459 &own_identity_data,
1460 &dan_identity_data,
1461 )
1462 .await
1463 .unwrap(),
1464 None,
1465 );
1466 assert_eq!(
1467 withheld_code_for_device_for_share_strategy(
1468 &get_device_data(
1469 &machine,
1470 KeyDistributionTestData::dan_id(),
1471 KeyDistributionTestData::dan_unsigned_device_id()
1472 )
1473 .await,
1474 CollectStrategy::OnlyTrustedDevices,
1475 &own_identity_data,
1476 &dan_identity_data,
1477 )
1478 .await
1479 .unwrap(),
1480 Some(WithheldCode::Unverified),
1481 );
1482 assert_eq!(
1483 withheld_code_for_device_for_share_strategy(
1484 &get_device_data(
1485 &machine,
1486 KeyDistributionTestData::dave_id(),
1487 KeyDistributionTestData::dave_device_id()
1488 )
1489 .await,
1490 CollectStrategy::OnlyTrustedDevices,
1491 &own_identity_data,
1492 &dave_identity_data,
1493 )
1494 .await
1495 .unwrap(),
1496 Some(WithheldCode::Unverified),
1497 );
1498 }
1499
1500 #[async_test]
1504 async fn test_error_on_unsigned_of_verified_users() {
1505 use VerificationViolationTestData as DataSet;
1506
1507 let machine = unsigned_of_verified_setup().await;
1509
1510 let carol_keys = DataSet::carol_keys_query_response_signed();
1512 machine.mark_request_as_sent(&TransactionId::new(), &carol_keys).await.unwrap();
1513
1514 let carol_identity =
1516 machine.get_identity(DataSet::carol_id(), None).await.unwrap().unwrap();
1517 assert!(carol_identity.other().unwrap().is_verified());
1518
1519 let carol_unsigned_device = machine
1520 .get_device(DataSet::carol_id(), DataSet::carol_unsigned_device_id(), None)
1521 .await
1522 .unwrap()
1523 .unwrap();
1524 assert!(!carol_unsigned_device.is_verified());
1525
1526 let encryption_settings = error_on_verification_problem_encryption_settings();
1528 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1529 let share_result = collect_session_recipients(
1530 machine.store(),
1531 vec![DataSet::bob_id(), DataSet::carol_id()].into_iter(),
1532 &encryption_settings,
1533 &group_session,
1534 )
1535 .await;
1536
1537 assert_let!(
1538 Err(OlmError::SessionRecipientCollectionError(
1539 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1540 )) = share_result
1541 );
1542
1543 assert_eq!(
1545 unverified_devices,
1546 BTreeMap::from([
1547 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1548 (
1549 DataSet::carol_id().to_owned(),
1550 vec![DataSet::carol_unsigned_device_id().to_owned()]
1551 ),
1552 ])
1553 );
1554
1555 #[cfg(feature = "experimental-send-custom-to-device")]
1556 {
1557 let all_devices = vec![
1558 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1559 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1560 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1561 .await,
1562 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_unsigned_device_id())
1563 .await,
1564 ];
1565
1566 let split_result = split_devices_for_share_strategy(
1567 machine.store(),
1568 all_devices,
1569 CollectStrategy::ErrorOnVerifiedUserProblem,
1570 )
1571 .await;
1572
1573 assert_let!(
1574 Err(OlmError::SessionRecipientCollectionError(
1575 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1576 unverified_devices
1577 )
1578 )) = split_result
1579 );
1580
1581 assert_eq!(
1583 unverified_devices,
1584 BTreeMap::from([
1585 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1586 (
1587 DataSet::carol_id().to_owned(),
1588 vec![DataSet::carol_unsigned_device_id().to_owned()]
1589 ),
1590 ])
1591 );
1592 }
1593
1594 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1595 let carol_identity_data = get_user_identity_data(&machine, DataSet::carol_id()).await;
1596
1597 assert_eq!(
1598 withheld_code_for_device_for_share_strategy(
1599 &get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1600 .await,
1601 CollectStrategy::ErrorOnVerifiedUserProblem,
1602 &own_identity_data,
1603 &carol_identity_data,
1604 )
1605 .await
1606 .unwrap(),
1607 None,
1608 );
1609 assert_let!(
1610 Err(OlmError::SessionRecipientCollectionError(
1611 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1612 )) = withheld_code_for_device_for_share_strategy(
1613 &get_device_data(
1614 &machine,
1615 DataSet::carol_id(),
1616 DataSet::carol_unsigned_device_id()
1617 )
1618 .await,
1619 CollectStrategy::ErrorOnVerifiedUserProblem,
1620 &own_identity_data,
1621 &carol_identity_data,
1622 )
1623 .await
1624 );
1625 }
1626
1627 #[async_test]
1631 async fn test_error_on_unsigned_of_verified_resolve_by_whitelisting() {
1632 use VerificationViolationTestData as DataSet;
1633
1634 let machine = unsigned_of_verified_setup().await;
1635
1636 machine
1638 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1639 .await
1640 .unwrap()
1641 .unwrap()
1642 .set_local_trust(LocalTrust::Ignored)
1643 .await
1644 .unwrap();
1645
1646 let encryption_settings = error_on_verification_problem_encryption_settings();
1647 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1648
1649 let share_result = collect_session_recipients(
1651 machine.store(),
1652 iter::once(DataSet::bob_id()),
1653 &encryption_settings,
1654 &group_session,
1655 )
1656 .await
1657 .unwrap();
1658
1659 assert_eq!(2, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1660 assert_eq!(0, share_result.withheld_devices.len());
1661
1662 #[cfg(feature = "experimental-send-custom-to-device")]
1663 {
1664 let all_devices = vec![
1665 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1666 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1667 ];
1668
1669 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1670 machine.store(),
1671 all_devices,
1672 CollectStrategy::ErrorOnVerifiedUserProblem,
1673 )
1674 .await
1675 .unwrap();
1676
1677 assert_eq!(shared_devices.len(), 2);
1678 assert_eq!(withheld_devices.len(), 0);
1679 }
1680
1681 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1682 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1683
1684 assert_eq!(
1685 withheld_code_for_device_for_share_strategy(
1686 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1687 CollectStrategy::ErrorOnVerifiedUserProblem,
1688 &own_identity_data,
1689 &bob_identity_data,
1690 )
1691 .await
1692 .unwrap(),
1693 None,
1694 );
1695 }
1696
1697 #[async_test]
1701 async fn test_error_on_unsigned_of_verified_resolve_by_blacklisting() {
1702 use VerificationViolationTestData as DataSet;
1703
1704 let machine = unsigned_of_verified_setup().await;
1705
1706 machine
1708 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1709 .await
1710 .unwrap()
1711 .unwrap()
1712 .set_local_trust(LocalTrust::BlackListed)
1713 .await
1714 .unwrap();
1715
1716 let encryption_settings = error_on_verification_problem_encryption_settings();
1717 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1718
1719 let share_result = collect_session_recipients(
1721 machine.store(),
1722 iter::once(DataSet::bob_id()),
1723 &encryption_settings,
1724 &group_session,
1725 )
1726 .await
1727 .unwrap();
1728
1729 assert_eq!(1, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1730 let withheld_list: Vec<_> = share_result
1731 .withheld_devices
1732 .iter()
1733 .map(|(d, code)| (d.device_id().to_owned(), code.clone()))
1734 .collect();
1735 assert_eq!(
1736 withheld_list,
1737 vec![(DataSet::bob_device_2_id().to_owned(), WithheldCode::Blacklisted)]
1738 );
1739
1740 let bob_device_2 =
1741 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await;
1742 #[cfg(feature = "experimental-send-custom-to-device")]
1743 {
1744 let bob_device_1 =
1745 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await;
1746 let all_devices = vec![bob_device_1.clone(), bob_device_2.clone()];
1747
1748 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1749 machine.store(),
1750 all_devices,
1751 CollectStrategy::ErrorOnVerifiedUserProblem,
1752 )
1753 .await
1754 .unwrap();
1755
1756 assert_eq!(shared_devices, vec![bob_device_1.clone()]);
1757 assert_eq!(withheld_devices, vec![(bob_device_2.clone(), WithheldCode::Blacklisted)]);
1758 }
1759
1760 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1761 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1762
1763 assert_eq!(
1764 withheld_code_for_device_for_share_strategy(
1765 &bob_device_2,
1766 CollectStrategy::ErrorOnVerifiedUserProblem,
1767 &own_identity_data,
1768 &bob_identity_data,
1769 )
1770 .await
1771 .unwrap(),
1772 Some(WithheldCode::Blacklisted),
1773 );
1774 }
1775
1776 #[async_test]
1780 async fn test_error_on_unsigned_of_verified_owner_is_us() {
1781 use VerificationViolationTestData as DataSet;
1782
1783 let machine = unsigned_of_verified_setup().await;
1784
1785 let mut own_keys = DataSet::own_keys_query_response_1().clone();
1787 own_keys.device_keys.insert(
1788 DataSet::own_id().to_owned(),
1789 BTreeMap::from([
1790 DataSet::own_signed_device_keys(),
1791 DataSet::own_unsigned_device_keys(),
1792 ]),
1793 );
1794 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1795
1796 let encryption_settings = error_on_verification_problem_encryption_settings();
1797 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1798 let share_result = collect_session_recipients(
1799 machine.store(),
1800 iter::once(DataSet::own_id()),
1801 &encryption_settings,
1802 &group_session,
1803 )
1804 .await;
1805
1806 assert_let!(
1807 Err(OlmError::SessionRecipientCollectionError(
1808 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1809 )) = share_result
1810 );
1811
1812 assert_eq!(
1814 unverified_devices,
1815 BTreeMap::from([(
1816 DataSet::own_id().to_owned(),
1817 vec![DataSet::own_unsigned_device_id()]
1818 ),])
1819 );
1820
1821 #[cfg(feature = "experimental-send-custom-to-device")]
1822 {
1823 let all_devices = vec![
1824 get_device_data(&machine, DataSet::own_id(), &DataSet::own_signed_device_id())
1825 .await,
1826 get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1827 .await,
1828 ];
1829
1830 let split_result = split_devices_for_share_strategy(
1831 machine.store(),
1832 all_devices,
1833 CollectStrategy::ErrorOnVerifiedUserProblem,
1834 )
1835 .await;
1836 assert_let!(
1837 Err(OlmError::SessionRecipientCollectionError(
1838 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1839 unverified_devices
1840 )
1841 )) = split_result
1842 );
1843
1844 assert_eq!(
1846 unverified_devices,
1847 BTreeMap::from([(
1848 DataSet::own_id().to_owned(),
1849 vec![DataSet::own_unsigned_device_id()]
1850 ),])
1851 );
1852 }
1853
1854 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1855 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
1856
1857 assert_let!(
1858 Err(OlmError::SessionRecipientCollectionError(
1859 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1860 )) = withheld_code_for_device_for_share_strategy(
1861 &get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1862 .await,
1863 CollectStrategy::ErrorOnVerifiedUserProblem,
1864 &own_identity_data,
1865 &own_user_identity_data,
1866 )
1867 .await
1868 );
1869 }
1870
1871 #[async_test]
1874 async fn test_should_not_error_on_unsigned_of_unverified() {
1875 use VerificationViolationTestData as DataSet;
1876
1877 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1878
1879 let own_keys = DataSet::own_keys_query_response_1();
1881 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1882
1883 machine
1885 .import_cross_signing_keys(CrossSigningKeyExport {
1886 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1887 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1888 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1889 })
1890 .await
1891 .unwrap();
1892
1893 let bob_keys = DataSet::bob_keys_query_response_rotated();
1895 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
1896
1897 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
1900 assert!(!bob_identity.other().unwrap().is_verified());
1901
1902 let bob_unsigned_device = machine
1903 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
1904 .await
1905 .unwrap()
1906 .unwrap();
1907 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1908
1909 let encryption_settings = error_on_verification_problem_encryption_settings();
1910 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1911 collect_session_recipients(
1912 machine.store(),
1913 iter::once(DataSet::bob_id()),
1914 &encryption_settings,
1915 &group_session,
1916 )
1917 .await
1918 .unwrap();
1919
1920 #[cfg(feature = "experimental-send-custom-to-device")]
1921 {
1922 let all_devices = vec![
1923 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1924 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1925 ];
1926
1927 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1928 machine.store(),
1929 all_devices,
1930 CollectStrategy::ErrorOnVerifiedUserProblem,
1931 )
1932 .await
1933 .unwrap();
1934
1935 assert_eq!(shared_devices.len(), 2);
1936 assert_eq!(withheld_devices.len(), 0);
1937 }
1938
1939 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1940 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1941
1942 assert_eq!(
1943 withheld_code_for_device_for_share_strategy(
1944 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1945 CollectStrategy::ErrorOnVerifiedUserProblem,
1946 &own_identity_data,
1947 &bob_identity_data,
1948 )
1949 .await
1950 .unwrap(),
1951 None,
1952 );
1953 }
1954
1955 #[async_test]
1958 async fn test_should_not_error_on_unsigned_of_signed_but_unverified() {
1959 use VerificationViolationTestData as DataSet;
1960
1961 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1962
1963 let keys_query = DataSet::own_keys_query_response_1();
1965 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1966
1967 let keys_query = DataSet::bob_keys_query_response_signed();
1969 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1970
1971 let bob_identity =
1974 machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap();
1975 assert!(
1976 bob_identity.own_identity.as_ref().unwrap().is_identity_signed(&bob_identity.inner)
1977 );
1978 assert!(!bob_identity.is_verified());
1979
1980 let bob_unsigned_device = machine
1981 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1982 .await
1983 .unwrap()
1984 .unwrap();
1985 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1986
1987 let encryption_settings = error_on_verification_problem_encryption_settings();
1989 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1990 collect_session_recipients(
1991 machine.store(),
1992 iter::once(DataSet::bob_id()),
1993 &encryption_settings,
1994 &group_session,
1995 )
1996 .await
1997 .unwrap();
1998
1999 #[cfg(feature = "experimental-send-custom-to-device")]
2000 {
2001 let all_devices = vec![
2002 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2003 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2004 ];
2005
2006 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
2007 machine.store(),
2008 all_devices,
2009 CollectStrategy::ErrorOnVerifiedUserProblem,
2010 )
2011 .await
2012 .unwrap();
2013
2014 assert_eq!(shared_devices.len(), 2);
2015 assert_eq!(withheld_devices.len(), 0);
2016 }
2017
2018 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2019 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2020
2021 assert_eq!(
2022 withheld_code_for_device_for_share_strategy(
2023 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2024 CollectStrategy::ErrorOnVerifiedUserProblem,
2025 &own_identity_data,
2026 &bob_identity_data,
2027 )
2028 .await
2029 .unwrap(),
2030 None,
2031 );
2032 }
2033
2034 #[async_test]
2038 async fn test_verified_user_changed_identity() {
2039 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2040
2041 let machine = unsigned_of_verified_setup().await;
2044
2045 let bob_keys = DataSet::bob_keys_query_response_rotated();
2047 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
2048
2049 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
2051 assert!(bob_identity.has_verification_violation());
2052
2053 let encryption_settings = error_on_verification_problem_encryption_settings();
2055 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2056 let share_result = collect_session_recipients(
2057 machine.store(),
2058 iter::once(DataSet::bob_id()),
2059 &encryption_settings,
2060 &group_session,
2061 )
2062 .await;
2063
2064 assert_let!(
2065 Err(OlmError::SessionRecipientCollectionError(
2066 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2067 )) = share_result
2068 );
2069 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2070
2071 #[cfg(feature = "experimental-send-custom-to-device")]
2072 {
2073 let all_devices = vec![
2074 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2075 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2076 ];
2077
2078 let split_result = split_devices_for_share_strategy(
2079 machine.store(),
2080 all_devices,
2081 CollectStrategy::ErrorOnVerifiedUserProblem,
2082 )
2083 .await;
2084 assert_let!(
2085 Err(OlmError::SessionRecipientCollectionError(
2086 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2087 )) = split_result
2088 );
2089 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2090 }
2091
2092 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2093 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2094
2095 assert_let!(
2096 Err(OlmError::SessionRecipientCollectionError(
2097 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2098 )) = withheld_code_for_device_for_share_strategy(
2099 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2100 CollectStrategy::ErrorOnVerifiedUserProblem,
2101 &own_identity_data,
2102 &bob_identity_data,
2103 )
2104 .await
2105 );
2106
2107 bob_identity.withdraw_verification().await.unwrap();
2109
2110 collect_session_recipients(
2111 machine.store(),
2112 iter::once(DataSet::bob_id()),
2113 &encryption_settings,
2114 &group_session,
2115 )
2116 .await
2117 .unwrap();
2118
2119 #[cfg(feature = "experimental-send-custom-to-device")]
2120 {
2121 let all_devices = vec![
2122 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2123 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2124 ];
2125
2126 split_devices_for_share_strategy(
2127 machine.store(),
2128 all_devices,
2129 CollectStrategy::ErrorOnVerifiedUserProblem,
2130 )
2131 .await
2132 .unwrap();
2133 }
2134
2135 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2136 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2137
2138 assert_eq!(
2139 withheld_code_for_device_for_share_strategy(
2140 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2141 CollectStrategy::ErrorOnVerifiedUserProblem,
2142 &own_identity_data,
2143 &bob_identity_data,
2144 )
2145 .await
2146 .unwrap(),
2147 None,
2148 );
2149 }
2150
2151 #[async_test]
2155 async fn test_own_verified_identity_changed() {
2156 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2157
2158 let machine = unsigned_of_verified_setup().await;
2160 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2161 assert!(own_identity.own().unwrap().is_verified());
2162
2163 let own_keys = DataSet::own_keys_query_response_2();
2165 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
2166
2167 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2168 assert!(!own_identity.is_verified());
2169
2170 let encryption_settings = error_on_verification_problem_encryption_settings();
2172 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2173 let share_result = collect_session_recipients(
2174 machine.store(),
2175 iter::once(DataSet::own_id()),
2176 &encryption_settings,
2177 &group_session,
2178 )
2179 .await;
2180
2181 assert_let!(
2182 Err(OlmError::SessionRecipientCollectionError(
2183 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2184 )) = share_result
2185 );
2186 assert_eq!(violating_users, vec![DataSet::own_id()]);
2187
2188 #[cfg(feature = "experimental-send-custom-to-device")]
2189 {
2190 let all_devices: Vec<DeviceData> =
2191 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2192
2193 let split_result = split_devices_for_share_strategy(
2194 machine.store(),
2195 all_devices,
2196 CollectStrategy::ErrorOnVerifiedUserProblem,
2197 )
2198 .await;
2199
2200 assert_let!(
2201 Err(OlmError::SessionRecipientCollectionError(
2202 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2203 )) = split_result
2204 );
2205 assert_eq!(violating_users, vec![DataSet::own_id()]);
2206 }
2207
2208 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2209 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2210
2211 assert_let!(
2212 Err(OlmError::SessionRecipientCollectionError(
2213 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2214 )) = withheld_code_for_device_for_share_strategy(
2215 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2216 CollectStrategy::ErrorOnVerifiedUserProblem,
2217 &own_identity_data,
2218 &own_user_identity_data,
2219 )
2220 .await
2221 );
2222
2223 own_identity.withdraw_verification().await.unwrap();
2225
2226 collect_session_recipients(
2227 machine.store(),
2228 iter::once(DataSet::own_id()),
2229 &encryption_settings,
2230 &group_session,
2231 )
2232 .await
2233 .unwrap();
2234
2235 #[cfg(feature = "experimental-send-custom-to-device")]
2236 {
2237 let all_devices: Vec<DeviceData> =
2238 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2239
2240 split_devices_for_share_strategy(
2241 machine.store(),
2242 all_devices,
2243 CollectStrategy::ErrorOnVerifiedUserProblem,
2244 )
2245 .await
2246 .unwrap();
2247 }
2248
2249 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2250 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2251
2252 withheld_code_for_device_for_share_strategy(
2253 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2254 CollectStrategy::ErrorOnVerifiedUserProblem,
2255 &own_identity_data,
2256 &own_user_identity_data,
2257 )
2258 .await
2259 .unwrap();
2260 }
2261
2262 mod dehydrated_device {
2265 use std::{collections::HashSet, iter};
2266
2267 use insta::{allow_duplicates, assert_json_snapshot, with_settings};
2268 use matrix_sdk_common::deserialized_responses::WithheldCode;
2269 use matrix_sdk_test::{
2270 async_test, ruma_response_to_json,
2271 test_json::keys_query_sets::{
2272 KeyDistributionTestData, KeyQueryResponseTemplate,
2273 KeyQueryResponseTemplateDeviceOptions,
2274 },
2275 };
2276 use ruma::{DeviceId, TransactionId, UserId, device_id, user_id};
2277 use vodozemac::{Curve25519PublicKey, Ed25519SecretKey};
2278
2279 use super::{
2280 all_devices_strategy_settings, create_test_outbound_group_session,
2281 error_on_verification_problem_encryption_settings, identity_based_strategy_settings,
2282 test_machine,
2283 };
2284 use crate::{
2285 EncryptionSettings, OlmMachine,
2286 session_manager::group_sessions::{
2287 CollectRecipientsResult, share_strategy::collect_session_recipients,
2288 },
2289 };
2290
2291 #[async_test]
2292 async fn test_all_devices_strategy_should_share_with_verified_dehydrated_device() {
2293 should_share_with_verified_dehydrated_device(&all_devices_strategy_settings()).await
2294 }
2295
2296 #[async_test]
2297 async fn test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device()
2298 {
2299 should_share_with_verified_dehydrated_device(
2300 &error_on_verification_problem_encryption_settings(),
2301 )
2302 .await
2303 }
2304
2305 #[async_test]
2306 async fn test_identity_based_strategy_should_share_with_verified_dehydrated_device() {
2307 should_share_with_verified_dehydrated_device(&identity_based_strategy_settings()).await
2308 }
2309
2310 async fn should_share_with_verified_dehydrated_device(
2315 encryption_settings: &EncryptionSettings,
2316 ) {
2317 let machine = test_machine().await;
2318
2319 let bob_user_id = user_id!("@bob:localhost");
2322 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2323 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2324 .with_dehydrated_device(bob_dehydrated_device_id, true)
2325 .build_response();
2326 allow_duplicates! {
2327 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2328 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2329 });
2330 }
2331 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2332
2333 let recips = share_test_session_and_collect_recipients(
2335 &machine,
2336 bob_user_id,
2337 encryption_settings,
2338 )
2339 .await;
2340
2341 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2343 }
2344
2345 #[async_test]
2346 async fn test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device() {
2347 should_not_share_with_unverified_dehydrated_device(&all_devices_strategy_settings())
2348 .await
2349 }
2350
2351 #[async_test]
2352 async fn test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device()
2353 {
2354 should_not_share_with_unverified_dehydrated_device(
2355 &error_on_verification_problem_encryption_settings(),
2356 )
2357 .await
2358 }
2359
2360 #[async_test]
2361 async fn test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device() {
2362 should_not_share_with_unverified_dehydrated_device(&identity_based_strategy_settings())
2363 .await
2364 }
2365
2366 async fn should_not_share_with_unverified_dehydrated_device(
2371 encryption_settings: &EncryptionSettings,
2372 ) {
2373 let machine = test_machine().await;
2374
2375 let bob_user_id = user_id!("@bob:localhost");
2378 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2379 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2380 .with_dehydrated_device(bob_dehydrated_device_id, false)
2381 .build_response();
2382 allow_duplicates! {
2383 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2384 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2385 });
2386 }
2387 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2388
2389 let recips = share_test_session_and_collect_recipients(
2391 &machine,
2392 bob_user_id,
2393 encryption_settings,
2394 )
2395 .await;
2396
2397 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2400 }
2401
2402 #[async_test]
2403 async fn test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user()
2404 {
2405 should_share_with_verified_device_of_pin_violation_user(
2406 &all_devices_strategy_settings(),
2407 )
2408 .await
2409 }
2410
2411 #[async_test]
2412 async fn test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user()
2413 {
2414 should_share_with_verified_device_of_pin_violation_user(
2415 &error_on_verification_problem_encryption_settings(),
2416 )
2417 .await
2418 }
2419
2420 #[async_test]
2421 async fn test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user()
2422 {
2423 should_share_with_verified_device_of_pin_violation_user(
2424 &identity_based_strategy_settings(),
2425 )
2426 .await
2427 }
2428
2429 async fn should_share_with_verified_device_of_pin_violation_user(
2434 encryption_settings: &EncryptionSettings,
2435 ) {
2436 let machine = test_machine().await;
2437
2438 let bob_user_id = user_id!("@bob:localhost");
2440 let keys_query =
2441 key_query_response_template_with_cross_signing(bob_user_id).build_response();
2442 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2443
2444 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2447 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2448 .with_dehydrated_device(bob_dehydrated_device_id, true)
2449 .build_response();
2450 allow_duplicates! {
2451 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2452 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2453 });
2454 }
2455 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2456
2457 let recips = share_test_session_and_collect_recipients(
2459 &machine,
2460 bob_user_id,
2461 encryption_settings,
2462 )
2463 .await;
2464
2465 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2467 }
2468
2469 #[async_test]
2470 async fn test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user()
2471 {
2472 should_not_share_with_dehydrated_device_of_verification_violation_user(
2473 &all_devices_strategy_settings(),
2474 )
2475 .await
2476 }
2477
2478 async fn should_not_share_with_dehydrated_device_of_verification_violation_user(
2481 encryption_settings: &EncryptionSettings,
2482 ) {
2483 let bob_user_id = user_id!("@bob:localhost");
2484 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2485 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2486 bob_user_id,
2487 bob_dehydrated_device_id,
2488 )
2489 .await;
2490
2491 let recips = share_test_session_and_collect_recipients(
2493 &machine,
2494 bob_user_id,
2495 encryption_settings,
2496 )
2497 .await;
2498
2499 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2502 }
2503
2504 #[async_test]
2505 async fn test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2506 {
2507 should_give_error_for_dehydrated_device_of_verification_violation_user(
2508 &error_on_verification_problem_encryption_settings(),
2509 )
2510 .await
2511 }
2512
2513 #[async_test]
2514 async fn test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2515 {
2516 should_give_error_for_dehydrated_device_of_verification_violation_user(
2520 &identity_based_strategy_settings(),
2521 )
2522 .await
2523 }
2524
2525 async fn should_give_error_for_dehydrated_device_of_verification_violation_user(
2529 encryption_settings: &EncryptionSettings,
2530 ) {
2531 let bob_user_id = user_id!("@bob:localhost");
2532 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2533 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2534 bob_user_id,
2535 bob_dehydrated_device_id,
2536 )
2537 .await;
2538
2539 let group_session = create_test_outbound_group_session(&machine, encryption_settings);
2540 let share_result = collect_session_recipients(
2541 machine.store(),
2542 iter::once(bob_user_id),
2543 encryption_settings,
2544 &group_session,
2545 )
2546 .await;
2547
2548 assert_matches::assert_matches!(
2551 share_result,
2552 Err(crate::OlmError::SessionRecipientCollectionError(
2553 crate::SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2554 ))
2555 );
2556 }
2557
2558 async fn prepare_machine_with_dehydrated_device_of_verification_violation_user(
2562 bob_user_id: &UserId,
2563 bob_dehydrated_device_id: &DeviceId,
2564 ) -> OlmMachine {
2565 let machine = test_machine().await;
2566
2567 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2569 .with_user_verification_signature(
2570 KeyDistributionTestData::me_id(),
2571 &KeyDistributionTestData::me_private_user_signing_key(),
2572 )
2573 .build_response();
2574 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2575
2576 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2579 .with_dehydrated_device(bob_dehydrated_device_id, true)
2580 .build_response();
2581 allow_duplicates! {
2582 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2583 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2584 });
2585 }
2586 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2587
2588 machine
2589 }
2590
2591 async fn share_test_session_and_collect_recipients(
2594 machine: &OlmMachine,
2595 target_user_id: &UserId,
2596 encryption_settings: &EncryptionSettings,
2597 ) -> CollectRecipientsResult {
2598 let group_session = create_test_outbound_group_session(machine, encryption_settings);
2599 collect_session_recipients(
2600 machine.store(),
2601 iter::once(target_user_id),
2602 encryption_settings,
2603 &group_session,
2604 )
2605 .await
2606 .unwrap()
2607 }
2608
2609 fn assert_shared_with(
2612 recips: CollectRecipientsResult,
2613 user_id: &UserId,
2614 device_ids: HashSet<&DeviceId>,
2615 ) {
2616 let bob_devices_shared: HashSet<_> = recips
2617 .devices
2618 .get(user_id)
2619 .unwrap_or_else(|| panic!("session not shared with {user_id}"))
2620 .iter()
2621 .map(|d| d.device_id())
2622 .collect();
2623 assert_eq!(bob_devices_shared, device_ids);
2624
2625 assert!(recips.withheld_devices.is_empty(), "Unexpected withheld messages");
2626 }
2627
2628 fn assert_withheld_to(
2631 recips: CollectRecipientsResult,
2632 bob_user_id: &UserId,
2633 bob_dehydrated_device_id: &DeviceId,
2634 ) {
2635 for (user, device_list) in recips.devices {
2637 assert_eq!(device_list.len(), 0, "session unexpectedly shared with {user}");
2638 }
2639
2640 assert_eq!(recips.withheld_devices.len(), 1);
2642 assert_eq!(recips.withheld_devices[0].0.user_id(), bob_user_id);
2643 assert_eq!(recips.withheld_devices[0].0.device_id(), bob_dehydrated_device_id);
2644 assert_eq!(recips.withheld_devices[0].1, WithheldCode::Unverified);
2645 }
2646
2647 fn key_query_response_template_with_cross_signing(
2650 user_id: &UserId,
2651 ) -> KeyQueryResponseTemplate {
2652 KeyQueryResponseTemplate::new(user_id.to_owned()).with_cross_signing_keys(
2653 Ed25519SecretKey::from_slice(b"master12master12master12master12"),
2654 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2655 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2656 )
2657 }
2658
2659 fn key_query_response_template_with_changed_cross_signing(
2663 bob_user_id: &UserId,
2664 ) -> KeyQueryResponseTemplate {
2665 KeyQueryResponseTemplate::new(bob_user_id.to_owned()).with_cross_signing_keys(
2666 Ed25519SecretKey::from_slice(b"newmaster__newmaster__newmaster_"),
2667 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2668 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2669 )
2670 }
2671
2672 trait KeyQueryResponseTemplateExt {
2673 fn with_dehydrated_device(
2674 self,
2675 device_id: &DeviceId,
2676 verified: bool,
2677 ) -> KeyQueryResponseTemplate;
2678 }
2679
2680 impl KeyQueryResponseTemplateExt for KeyQueryResponseTemplate {
2681 fn with_dehydrated_device(
2683 self,
2684 device_id: &DeviceId,
2685 verified: bool,
2686 ) -> KeyQueryResponseTemplate {
2687 self.with_device(
2688 device_id,
2689 &Curve25519PublicKey::from(b"curvepubcurvepubcurvepubcurvepub".to_owned()),
2690 &Ed25519SecretKey::from_slice(b"device12device12device12device12"),
2691 KeyQueryResponseTemplateDeviceOptions::new()
2692 .dehydrated(true)
2693 .verified(verified),
2694 )
2695 }
2696 }
2697 }
2698
2699 #[async_test]
2700 async fn test_share_with_identity_strategy() {
2701 let machine = test_machine().await;
2702 import_known_users_to_test_machine(&machine).await;
2703
2704 let encryption_settings = identity_based_strategy_settings();
2705
2706 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2707
2708 let share_result = collect_session_recipients(
2709 machine.store(),
2710 vec![
2711 KeyDistributionTestData::dan_id(),
2712 KeyDistributionTestData::dave_id(),
2713 KeyDistributionTestData::good_id(),
2714 ]
2715 .into_iter(),
2716 &encryption_settings,
2717 &group_session,
2718 )
2719 .await
2720 .unwrap();
2721
2722 assert!(!share_result.should_rotate);
2723
2724 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
2725 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
2726 assert!(dave_devices_shared.unwrap().is_empty());
2728
2729 assert_eq!(good_devices_shared.unwrap().len(), 2);
2731
2732 let dan_devices_shared =
2735 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
2736
2737 assert_eq!(dan_devices_shared.len(), 1);
2738 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
2739 assert_eq!(
2740 dan_device_that_will_get_the_key.device_id().as_str(),
2741 KeyDistributionTestData::dan_signed_device_id()
2742 );
2743
2744 let (_, code) = share_result
2746 .withheld_devices
2747 .iter()
2748 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
2749 .expect("This dan's device should receive a withheld code");
2750
2751 assert_eq!(code, &WithheldCode::Unverified);
2752
2753 let (_, code) = share_result
2755 .withheld_devices
2756 .iter()
2757 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
2758 .expect("This dave device should receive a withheld code");
2759
2760 assert_eq!(code, &WithheldCode::Unverified);
2761 }
2762
2763 #[async_test]
2766 async fn test_share_identity_strategy_no_cross_signing() {
2767 let machine: OlmMachine = OlmMachine::new(
2770 KeyDistributionTestData::me_id(),
2771 KeyDistributionTestData::me_device_id(),
2772 )
2773 .await;
2774
2775 let keys_query = KeyDistributionTestData::dan_keys_query_response();
2776 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2777
2778 let fake_room_id = room_id!("!roomid:localhost");
2779
2780 let encryption_settings = identity_based_strategy_settings();
2781
2782 let request_result = machine
2783 .share_room_key(
2784 fake_room_id,
2785 iter::once(KeyDistributionTestData::dan_id()),
2786 encryption_settings.clone(),
2787 )
2788 .await;
2789
2790 assert_matches!(
2791 request_result,
2792 Err(OlmError::SessionRecipientCollectionError(
2793 SessionRecipientCollectionError::CrossSigningNotSetup
2794 ))
2795 );
2796
2797 let keys_query = KeyDistributionTestData::me_keys_query_response();
2801 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2802
2803 let request_result = machine
2804 .share_room_key(
2805 fake_room_id,
2806 iter::once(KeyDistributionTestData::dan_id()),
2807 encryption_settings.clone(),
2808 )
2809 .await;
2810
2811 assert_matches!(
2812 request_result,
2813 Err(OlmError::SessionRecipientCollectionError(
2814 SessionRecipientCollectionError::SendingFromUnverifiedDevice
2815 ))
2816 );
2817
2818 machine
2821 .import_cross_signing_keys(CrossSigningKeyExport {
2822 master_key: KeyDistributionTestData::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
2823 self_signing_key: KeyDistributionTestData::SELF_SIGNING_KEY_PRIVATE_EXPORT
2824 .to_owned()
2825 .into(),
2826 user_signing_key: KeyDistributionTestData::USER_SIGNING_KEY_PRIVATE_EXPORT
2827 .to_owned()
2828 .into(),
2829 })
2830 .await
2831 .unwrap();
2832
2833 let requests = machine
2834 .share_room_key(
2835 fake_room_id,
2836 iter::once(KeyDistributionTestData::dan_id()),
2837 encryption_settings.clone(),
2838 )
2839 .await
2840 .unwrap();
2841
2842 assert_eq!(requests.len(), 1);
2845 }
2846
2847 #[async_test]
2851 async fn test_share_identity_strategy_report_verification_violation() {
2852 let machine: OlmMachine = OlmMachine::new(
2853 KeyDistributionTestData::me_id(),
2854 KeyDistributionTestData::me_device_id(),
2855 )
2856 .await;
2857
2858 machine.bootstrap_cross_signing(false).await.unwrap();
2859
2860 let user1 = IdentityChangeDataSet::user_id();
2862 let user2 = MaloIdentityChangeDataSet::user_id();
2863
2864 let keys_query = IdentityChangeDataSet::key_query_with_identity_a();
2866 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2867
2868 let keys_query = MaloIdentityChangeDataSet::initial_key_query();
2869 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2870
2871 let keys_query = IdentityChangeDataSet::key_query_with_identity_b();
2875 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2876 machine
2877 .get_identity(user1, None)
2878 .await
2879 .unwrap()
2880 .unwrap()
2881 .other()
2882 .unwrap()
2883 .mark_as_previously_verified()
2884 .await
2885 .unwrap();
2886
2887 let keys_query = MaloIdentityChangeDataSet::updated_key_query();
2888 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2889 machine
2890 .get_identity(user2, None)
2891 .await
2892 .unwrap()
2893 .unwrap()
2894 .other()
2895 .unwrap()
2896 .mark_as_previously_verified()
2897 .await
2898 .unwrap();
2899
2900 let fake_room_id = room_id!("!roomid:localhost");
2901
2902 let encryption_settings = identity_based_strategy_settings();
2904
2905 let request_result = machine
2906 .share_room_key(
2907 fake_room_id,
2908 vec![user1, user2].into_iter(),
2909 encryption_settings.clone(),
2910 )
2911 .await;
2912
2913 assert_let!(
2916 Err(OlmError::SessionRecipientCollectionError(
2917 SessionRecipientCollectionError::VerifiedUserChangedIdentity(affected_users)
2918 )) = request_result
2919 );
2920 assert_eq!(2, affected_users.len());
2922
2923 machine
2925 .get_identity(user1, None)
2926 .await
2927 .unwrap()
2928 .unwrap()
2929 .withdraw_verification()
2930 .await
2931 .unwrap();
2932
2933 let verification_request = machine
2935 .get_identity(user2, None)
2936 .await
2937 .unwrap()
2938 .unwrap()
2939 .other()
2940 .unwrap()
2941 .verify()
2942 .await
2943 .unwrap();
2944
2945 let master_key =
2946 &machine.get_identity(user2, None).await.unwrap().unwrap().other().unwrap().master_key;
2947
2948 let my_identity = machine
2949 .get_identity(KeyDistributionTestData::me_id(), None)
2950 .await
2951 .expect("Should not fail to find own identity")
2952 .expect("Our own identity should not be missing")
2953 .own()
2954 .expect("Our own identity should be of type Own");
2955
2956 let msk = json!({ user2: serde_json::to_value(master_key).expect("Should not fail to serialize")});
2957 let ssk =
2958 serde_json::to_value(&MaloIdentityChangeDataSet::updated_key_query().self_signing_keys)
2959 .expect("Should not fail to serialize");
2960
2961 let kq_response = simulate_key_query_response_for_verification(
2962 verification_request,
2963 my_identity,
2964 KeyDistributionTestData::me_id(),
2965 user2,
2966 msk,
2967 ssk,
2968 );
2969
2970 machine
2971 .mark_request_as_sent(
2972 &TransactionId::new(),
2973 crate::types::requests::AnyIncomingResponse::KeysQuery(&kq_response),
2974 )
2975 .await
2976 .unwrap();
2977
2978 assert!(machine.get_identity(user2, None).await.unwrap().unwrap().is_verified());
2979
2980 machine
2982 .share_room_key(
2983 fake_room_id,
2984 vec![user1, user2].into_iter(),
2985 encryption_settings.clone(),
2986 )
2987 .await
2988 .unwrap();
2989 }
2990
2991 #[async_test]
2992 async fn test_should_rotate_based_on_visibility() {
2993 let machine = test_machine().await;
2994 import_known_users_to_test_machine(&machine).await;
2995
2996 let strategy = CollectStrategy::AllDevices;
2997
2998 let encryption_settings = EncryptionSettings {
2999 sharing_strategy: strategy.clone(),
3000 history_visibility: HistoryVisibility::Invited,
3001 ..Default::default()
3002 };
3003
3004 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3005
3006 let _ = collect_session_recipients(
3007 machine.store(),
3008 vec![KeyDistributionTestData::dan_id()].into_iter(),
3009 &encryption_settings,
3010 &group_session,
3011 )
3012 .await
3013 .unwrap();
3014
3015 let encryption_settings = EncryptionSettings {
3017 sharing_strategy: strategy.clone(),
3018 history_visibility: HistoryVisibility::Shared,
3019 ..Default::default()
3020 };
3021
3022 let share_result = collect_session_recipients(
3023 machine.store(),
3024 vec![KeyDistributionTestData::dan_id()].into_iter(),
3025 &encryption_settings,
3026 &group_session,
3027 )
3028 .await
3029 .unwrap();
3030
3031 assert!(share_result.should_rotate);
3032 }
3033
3034 #[async_test]
3038 async fn test_should_rotate_based_on_device_excluded() {
3039 let machine = test_machine().await;
3040 import_known_users_to_test_machine(&machine).await;
3041
3042 let encryption_settings = all_devices_strategy_settings();
3043 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3044 let sender_key = machine.identity_keys().curve25519;
3045
3046 group_session
3047 .mark_shared_with(
3048 KeyDistributionTestData::dan_id(),
3049 KeyDistributionTestData::dan_signed_device_id(),
3050 sender_key,
3051 )
3052 .await;
3053 group_session
3054 .mark_shared_with(
3055 KeyDistributionTestData::dan_id(),
3056 KeyDistributionTestData::dan_unsigned_device_id(),
3057 sender_key,
3058 )
3059 .await;
3060
3061 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3063 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3064
3065 let share_result = collect_session_recipients(
3067 machine.store(),
3068 vec![KeyDistributionTestData::dan_id()].into_iter(),
3069 &encryption_settings,
3070 &group_session,
3071 )
3072 .await
3073 .unwrap();
3074
3075 assert!(share_result.should_rotate);
3076 }
3077
3078 #[async_test]
3081 async fn test_should_rotate_based_on_device_with_pending_request_excluded() {
3082 let machine = test_machine().await;
3083 import_known_users_to_test_machine(&machine).await;
3084
3085 let encryption_settings = all_devices_strategy_settings();
3086 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3087 let sender_key = machine.identity_keys().curve25519;
3088
3089 let dan_user = KeyDistributionTestData::dan_id();
3090 let dan_dev1 = KeyDistributionTestData::dan_signed_device_id();
3091 let dan_dev2 = KeyDistributionTestData::dan_unsigned_device_id();
3092
3093 group_session.mark_shared_with(dan_user, dan_dev1, sender_key).await;
3095
3096 {
3097 let share_infos = BTreeMap::from([(
3099 dan_user.to_owned(),
3100 BTreeMap::from([(
3101 dan_dev2.to_owned(),
3102 ShareInfo::new_shared(sender_key, 0, SequenceNumber::default()),
3103 )]),
3104 )]);
3105
3106 let txid = TransactionId::new();
3107 let req = Arc::new(ToDeviceRequest::for_recipients(
3108 dan_user,
3109 vec![dan_dev2.to_owned()],
3110 &ruma::events::AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent),
3111 txid.clone(),
3112 ));
3113 group_session.add_request(txid, req, share_infos);
3114 }
3115
3116 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3118 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3119
3120 let share_result = collect_session_recipients(
3122 machine.store(),
3123 vec![KeyDistributionTestData::dan_id()].into_iter(),
3124 &encryption_settings,
3125 &group_session,
3126 )
3127 .await
3128 .unwrap();
3129
3130 assert!(share_result.should_rotate);
3131 }
3132
3133 #[async_test]
3136 async fn test_should_not_rotate_if_keys_were_withheld() {
3137 let machine = test_machine().await;
3138 import_known_users_to_test_machine(&machine).await;
3139
3140 let encryption_settings = all_devices_strategy_settings();
3141 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3142 let fake_room_id = group_session.room_id();
3143
3144 let requests = machine
3147 .share_room_key(
3148 fake_room_id,
3149 vec![KeyDistributionTestData::dan_id()].into_iter(),
3150 encryption_settings.clone(),
3151 )
3152 .await
3153 .unwrap();
3154
3155 for r in requests {
3156 machine
3157 .inner
3158 .group_session_manager
3159 .mark_request_as_sent(r.as_ref().txn_id.as_ref())
3160 .await
3161 .unwrap();
3162 }
3163
3164 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3166 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3167
3168 let share_result = collect_session_recipients(
3170 machine.store(),
3171 vec![KeyDistributionTestData::dan_id()].into_iter(),
3172 &encryption_settings,
3173 &group_session,
3174 )
3175 .await
3176 .unwrap();
3177
3178 assert!(!share_result.should_rotate);
3179 }
3180
3181 async fn unsigned_of_verified_setup() -> OlmMachine {
3189 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
3190
3191 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
3192
3193 let own_keys = DataSet::own_keys_query_response_1();
3195 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
3196
3197 machine
3199 .import_cross_signing_keys(CrossSigningKeyExport {
3200 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
3201 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3202 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3203 })
3204 .await
3205 .unwrap();
3206
3207 let bob_keys = DataSet::bob_keys_query_response_signed();
3209 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
3210
3211 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
3214 assert!(bob_identity.other().unwrap().is_verified());
3215
3216 let bob_signed_device = machine
3217 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
3218 .await
3219 .unwrap()
3220 .unwrap();
3221 assert!(bob_signed_device.is_verified());
3222 assert!(bob_signed_device.device_owner_identity.is_some());
3223
3224 let bob_unsigned_device = machine
3225 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
3226 .await
3227 .unwrap()
3228 .unwrap();
3229 assert!(!bob_unsigned_device.is_verified());
3230
3231 machine
3232 }
3233
3234 fn all_devices_strategy_settings() -> EncryptionSettings {
3236 EncryptionSettings { sharing_strategy: CollectStrategy::AllDevices, ..Default::default() }
3237 }
3238
3239 fn error_on_verification_problem_encryption_settings() -> EncryptionSettings {
3242 EncryptionSettings {
3243 sharing_strategy: CollectStrategy::ErrorOnVerifiedUserProblem,
3244 ..Default::default()
3245 }
3246 }
3247
3248 fn identity_based_strategy_settings() -> EncryptionSettings {
3250 EncryptionSettings {
3251 sharing_strategy: CollectStrategy::IdentityBasedStrategy,
3252 ..Default::default()
3253 }
3254 }
3255
3256 fn create_test_outbound_group_session(
3259 machine: &OlmMachine,
3260 encryption_settings: &EncryptionSettings,
3261 ) -> OutboundGroupSession {
3262 OutboundGroupSession::new(
3263 machine.device_id().into(),
3264 Arc::new(machine.identity_keys()),
3265 room_id!("!roomid:localhost"),
3266 encryption_settings.clone(),
3267 )
3268 .expect("creating an outbound group session should not fail")
3269 }
3270}