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]
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 && !recipients.should_rotate
393 {
394 recipients.should_rotate =
395 is_session_overshared_for_user(outbound, user_id, &recipient_devices.allowed_devices)
396 }
397
398 recipients
399 .devices
400 .entry(user_id.to_owned())
401 .or_default()
402 .extend(recipient_devices.allowed_devices);
403 recipients.withheld_devices.extend(recipient_devices.denied_devices_with_code);
404}
405
406fn is_session_overshared_for_user(
422 outbound_session: &OutboundGroupSession,
423 user_id: &UserId,
424 recipient_devices: &[DeviceData],
425) -> bool {
426 let recipient_device_ids: BTreeSet<&DeviceId> =
428 recipient_devices.iter().map(|d| d.device_id()).collect();
429
430 let view = outbound_session.sharing_view();
431 let newly_deleted_or_blacklisted: BTreeSet<&DeviceId> = view
432 .iter_shares(Some(user_id), None)
433 .filter_map(|(_user_id, device_id, info)| {
434 if matches!(info, ShareInfo::Shared(_)) && !recipient_device_ids.contains(device_id) {
438 Some(device_id)
439 } else {
440 None
441 }
442 })
443 .collect();
444
445 let should_rotate = !newly_deleted_or_blacklisted.is_empty();
446 if should_rotate {
447 debug!(
448 "Rotating a room key due to these devices being deleted/blacklisted {:?}",
449 newly_deleted_or_blacklisted,
450 );
451 }
452 should_rotate
453}
454
455#[cfg(feature = "experimental-send-custom-to-device")]
456pub(crate) async fn split_devices_for_share_strategy(
458 store: &Store,
459 devices: Vec<DeviceData>,
460 share_strategy: CollectStrategy,
461) -> OlmResult<(Vec<DeviceData>, Vec<(DeviceData, WithheldCode)>)> {
462 let own_identity = store.get_user_identity(store.user_id()).await?.and_then(|i| i.into_own());
463
464 let mut verified_users_with_new_identities: BTreeSet<OwnedUserId> = Default::default();
465
466 let mut allowed_devices: Vec<DeviceData> = Default::default();
467 let mut blocked_devices: Vec<(DeviceData, WithheldCode)> = Default::default();
468
469 let mut user_identities_cache: BTreeMap<OwnedUserId, Option<UserIdentityData>> =
470 Default::default();
471 let mut get_user_identity = async move |user_id| -> OlmResult<_> {
472 match user_identities_cache.get(user_id) {
473 Some(user_identity) => Ok(user_identity.clone()),
474 None => {
475 let user_identity = store.get_user_identity(user_id).await?;
476 user_identities_cache.insert(user_id.to_owned(), user_identity.clone());
477 Ok(user_identity)
478 }
479 }
480 };
481
482 match share_strategy {
483 CollectStrategy::AllDevices => {
484 for device in devices.iter() {
485 let user_id = device.user_id();
486 let device_owner_identity = get_user_identity(user_id).await?;
487
488 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
489 device,
490 &own_identity,
491 &device_owner_identity,
492 ) {
493 blocked_devices.push((device.clone(), withheld_code));
494 } else {
495 allowed_devices.push(device.clone());
496 }
497 }
498 }
499
500 CollectStrategy::ErrorOnVerifiedUserProblem => {
501 let mut unsigned_devices_of_verified_users: BTreeMap<OwnedUserId, Vec<OwnedDeviceId>> =
507 Default::default();
508 let mut add_device_to_unsigned_devices_map = |user_id: &UserId, device: &DeviceData| {
509 let device_id = device.device_id().to_owned();
510 if let Some(devices) = unsigned_devices_of_verified_users.get_mut(user_id) {
511 devices.push(device_id);
512 } else {
513 unsigned_devices_of_verified_users.insert(user_id.to_owned(), vec![device_id]);
514 }
515 };
516
517 for device in devices.iter() {
518 let user_id = device.user_id();
519 let device_owner_identity = get_user_identity(user_id).await?;
520
521 if has_identity_verification_violation(
522 own_identity.as_ref(),
523 device_owner_identity.as_ref(),
524 ) {
525 verified_users_with_new_identities.insert(user_id.to_owned());
526 } else {
527 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
528 device,
529 own_identity.as_ref(),
530 device_owner_identity.as_ref(),
531 ) {
532 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
533 allowed_devices.push(device.clone())
534 }
535 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
536 blocked_devices.push((device.clone(), code))
537 }
538 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
539 add_device_to_unsigned_devices_map(user_id, device);
540 }
541 }
542 }
543 }
544
545 if !unsigned_devices_of_verified_users.is_empty() {
546 return Err(OlmError::SessionRecipientCollectionError(
547 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
548 unsigned_devices_of_verified_users,
549 ),
550 ));
551 }
552 }
553
554 CollectStrategy::IdentityBasedStrategy => {
555 match &own_identity {
558 None => {
559 return Err(OlmError::SessionRecipientCollectionError(
560 SessionRecipientCollectionError::CrossSigningNotSetup,
561 ));
562 }
563 Some(identity) if !identity.is_verified() => {
564 return Err(OlmError::SessionRecipientCollectionError(
565 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
566 ));
567 }
568 Some(_) => (),
569 }
570
571 for device in devices.iter() {
572 let user_id = device.user_id();
573 let device_owner_identity = get_user_identity(user_id).await?;
574
575 if has_identity_verification_violation(
576 own_identity.as_ref(),
577 device_owner_identity.as_ref(),
578 ) {
579 verified_users_with_new_identities.insert(user_id.to_owned());
580 } else if let Some(device_owner_identity) = device_owner_identity {
581 if let Some(withheld_code) =
582 withheld_code_for_device_with_owner_for_identity_based_strategy(
583 device,
584 &device_owner_identity,
585 )
586 {
587 blocked_devices.push((device.clone(), withheld_code));
588 } else {
589 allowed_devices.push(device.clone());
590 }
591 } else {
592 panic!("Should have verification violation if device_owner_identity is None")
593 }
594 }
595 }
596
597 CollectStrategy::OnlyTrustedDevices => {
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 let Some(withheld_code) =
603 withheld_code_for_device_for_only_trusted_devices_strategy(
604 device,
605 &own_identity,
606 &device_owner_identity,
607 )
608 {
609 blocked_devices.push((device.clone(), withheld_code));
610 } else {
611 allowed_devices.push(device.clone());
612 }
613 }
614 }
615 }
616
617 if !verified_users_with_new_identities.is_empty() {
618 return Err(OlmError::SessionRecipientCollectionError(
619 SessionRecipientCollectionError::VerifiedUserChangedIdentity(
620 verified_users_with_new_identities.into_iter().collect(),
621 ),
622 ));
623 }
624
625 Ok((allowed_devices, blocked_devices))
626}
627
628pub(crate) async fn withheld_code_for_device_for_share_strategy(
629 device: &DeviceData,
630 share_strategy: CollectStrategy,
631 own_identity: &Option<OwnUserIdentityData>,
632 device_owner_identity: &Option<UserIdentityData>,
633) -> OlmResult<Option<WithheldCode>> {
634 match share_strategy {
635 CollectStrategy::AllDevices => Ok(withheld_code_for_device_for_all_devices_strategy(
636 device,
637 own_identity,
638 device_owner_identity,
639 )),
640 CollectStrategy::ErrorOnVerifiedUserProblem => {
641 if has_identity_verification_violation(
642 own_identity.as_ref(),
643 device_owner_identity.as_ref(),
644 ) {
645 return Err(OlmError::SessionRecipientCollectionError(
646 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
647 device.user_id().to_owned(),
648 ]),
649 ));
650 }
651 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
652 device,
653 own_identity.as_ref(),
654 device_owner_identity.as_ref(),
655 ) {
656 ErrorOnVerifiedUserProblemDeviceDecision::Ok => Ok(None),
657 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => Ok(Some(code)),
658 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
659 Err(OlmError::SessionRecipientCollectionError(
660 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
661 BTreeMap::from([(
662 device.user_id().to_owned(),
663 vec![device.device_id().to_owned()],
664 )]),
665 ),
666 ))
667 }
668 }
669 }
670 CollectStrategy::IdentityBasedStrategy => {
671 match &own_identity {
674 None => {
675 return Err(OlmError::SessionRecipientCollectionError(
676 SessionRecipientCollectionError::CrossSigningNotSetup,
677 ));
678 }
679 Some(identity) if !identity.is_verified() => {
680 return Err(OlmError::SessionRecipientCollectionError(
681 SessionRecipientCollectionError::SendingFromUnverifiedDevice,
682 ));
683 }
684 Some(_) => (),
685 }
686
687 if has_identity_verification_violation(
688 own_identity.as_ref(),
689 device_owner_identity.as_ref(),
690 ) {
691 Err(OlmError::SessionRecipientCollectionError(
692 SessionRecipientCollectionError::VerifiedUserChangedIdentity(vec![
693 device.user_id().to_owned(),
694 ]),
695 ))
696 } else if let Some(device_owner_identity) = device_owner_identity {
697 Ok(withheld_code_for_device_with_owner_for_identity_based_strategy(
698 device,
699 device_owner_identity,
700 ))
701 } else {
702 panic!("Should have verification violation if device_owner_identity is None")
703 }
704 }
705 CollectStrategy::OnlyTrustedDevices => {
706 Ok(withheld_code_for_device_for_only_trusted_devices_strategy(
707 device,
708 own_identity,
709 device_owner_identity,
710 ))
711 }
712 }
713}
714
715#[derive(Default)]
722struct RecipientDevicesForUser {
723 allowed_devices: Vec<DeviceData>,
725 denied_devices_with_code: Vec<(DeviceData, WithheldCode)>,
727}
728
729enum ErrorOnVerifiedUserProblemResult {
732 UnsignedDevicesOfVerifiedUser(Vec<OwnedDeviceId>),
736
737 Devices(RecipientDevicesForUser),
739}
740
741fn split_devices_for_user_for_all_devices_strategy(
744 user_devices: HashMap<OwnedDeviceId, DeviceData>,
745 own_identity: &Option<OwnUserIdentityData>,
746 device_owner_identity: &Option<UserIdentityData>,
747) -> RecipientDevicesForUser {
748 let (left, right) = user_devices.into_values().partition_map(|d| {
749 if let Some(withheld_code) = withheld_code_for_device_for_all_devices_strategy(
750 &d,
751 own_identity,
752 device_owner_identity,
753 ) {
754 Either::Right((d, withheld_code))
755 } else {
756 Either::Left(d)
757 }
758 });
759
760 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
761}
762
763fn withheld_code_for_device_for_all_devices_strategy(
767 device_data: &DeviceData,
768 own_identity: &Option<OwnUserIdentityData>,
769 device_owner_identity: &Option<UserIdentityData>,
770) -> Option<WithheldCode> {
771 if device_data.is_blacklisted() {
772 Some(WithheldCode::Blacklisted)
773 } else if device_data.is_dehydrated()
774 && should_withhold_to_dehydrated_device(
775 device_data,
776 own_identity.as_ref(),
777 device_owner_identity.as_ref(),
778 )
779 {
780 Some(WithheldCode::Unverified)
781 } else {
782 None
783 }
784}
785
786fn should_withhold_to_dehydrated_device(
795 device: &DeviceData,
796 own_identity: Option<&OwnUserIdentityData>,
797 device_owner_identity: Option<&UserIdentityData>,
798) -> bool {
799 device_owner_identity.is_none_or(|owner_id| {
800 !device.is_cross_signed_by_owner(owner_id) ||
802
803 (owner_id.was_previously_verified() && !is_user_verified(own_identity, owner_id))
805 })
806}
807
808fn split_devices_for_user_for_error_on_verified_user_problem_strategy(
821 user_devices: HashMap<OwnedDeviceId, DeviceData>,
822 own_identity: &Option<OwnUserIdentityData>,
823 device_owner_identity: &Option<UserIdentityData>,
824) -> ErrorOnVerifiedUserProblemResult {
825 let mut recipient_devices = RecipientDevicesForUser::default();
826
827 let mut unsigned_devices_of_verified_users: Option<Vec<OwnedDeviceId>> = None;
830
831 for d in user_devices.into_values() {
832 match handle_device_for_user_for_error_on_verified_user_problem_strategy(
833 &d,
834 own_identity.as_ref(),
835 device_owner_identity.as_ref(),
836 ) {
837 ErrorOnVerifiedUserProblemDeviceDecision::Ok => {
838 recipient_devices.allowed_devices.push(d)
839 }
840 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(code) => {
841 recipient_devices.denied_devices_with_code.push((d, code))
842 }
843 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified => {
844 unsigned_devices_of_verified_users
845 .get_or_insert_with(Vec::default)
846 .push(d.device_id().to_owned())
847 }
848 }
849 }
850
851 if let Some(devices) = unsigned_devices_of_verified_users {
852 ErrorOnVerifiedUserProblemResult::UnsignedDevicesOfVerifiedUser(devices)
853 } else {
854 ErrorOnVerifiedUserProblemResult::Devices(recipient_devices)
855 }
856}
857
858enum ErrorOnVerifiedUserProblemDeviceDecision {
861 Ok,
862 Withhold(WithheldCode),
863 UnsignedOfVerified,
864}
865
866fn handle_device_for_user_for_error_on_verified_user_problem_strategy(
867 device: &DeviceData,
868 own_identity: Option<&OwnUserIdentityData>,
869 device_owner_identity: Option<&UserIdentityData>,
870) -> ErrorOnVerifiedUserProblemDeviceDecision {
871 if device.is_blacklisted() {
872 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Blacklisted)
873 } else if device.local_trust_state() == LocalTrust::Ignored {
874 ErrorOnVerifiedUserProblemDeviceDecision::Ok
876 } else if is_unsigned_device_of_verified_user(own_identity, device_owner_identity, device) {
877 ErrorOnVerifiedUserProblemDeviceDecision::UnsignedOfVerified
878 } else if device.is_dehydrated()
879 && device_owner_identity.is_none_or(|owner_id| {
880 !device.is_cross_signed_by_owner(owner_id)
883 })
884 {
885 ErrorOnVerifiedUserProblemDeviceDecision::Withhold(WithheldCode::Unverified)
886 } else {
887 ErrorOnVerifiedUserProblemDeviceDecision::Ok
888 }
889}
890
891fn split_devices_for_user_for_identity_based_strategy(
892 user_devices: HashMap<OwnedDeviceId, DeviceData>,
893 device_owner_identity: &Option<UserIdentityData>,
894) -> RecipientDevicesForUser {
895 match device_owner_identity {
896 None => {
897 RecipientDevicesForUser {
900 allowed_devices: Vec::default(),
901 denied_devices_with_code: user_devices
902 .into_values()
903 .map(|d| (d, WithheldCode::Unverified))
904 .collect(),
905 }
906 }
907 Some(device_owner_identity) => {
908 let (recipients, withheld_recipients): (
910 Vec<DeviceData>,
911 Vec<(DeviceData, WithheldCode)>,
912 ) = user_devices.into_values().partition_map(|d| {
913 if let Some(withheld_code) =
914 withheld_code_for_device_with_owner_for_identity_based_strategy(
915 &d,
916 device_owner_identity,
917 )
918 {
919 Either::Right((d, withheld_code))
920 } else {
921 Either::Left(d)
922 }
923 });
924 RecipientDevicesForUser {
925 allowed_devices: recipients,
926 denied_devices_with_code: withheld_recipients,
927 }
928 }
929 }
930}
931
932fn withheld_code_for_device_with_owner_for_identity_based_strategy(
936 device_data: &DeviceData,
937 device_owner_identity: &UserIdentityData,
938) -> Option<WithheldCode> {
939 if device_data.is_cross_signed_by_owner(device_owner_identity) {
940 None
941 } else {
942 Some(WithheldCode::Unverified)
943 }
944}
945
946fn split_devices_for_user_for_only_trusted_devices(
949 user_devices: HashMap<OwnedDeviceId, DeviceData>,
950 own_identity: &Option<OwnUserIdentityData>,
951 device_owner_identity: &Option<UserIdentityData>,
952) -> RecipientDevicesForUser {
953 let (left, right) = user_devices.into_values().partition_map(|d| {
954 if let Some(withheld_code) = withheld_code_for_device_for_only_trusted_devices_strategy(
955 &d,
956 own_identity,
957 device_owner_identity,
958 ) {
959 Either::Right((d, withheld_code))
960 } else {
961 Either::Left(d)
962 }
963 });
964 RecipientDevicesForUser { allowed_devices: left, denied_devices_with_code: right }
965}
966
967fn withheld_code_for_device_for_only_trusted_devices_strategy(
971 device_data: &DeviceData,
972 own_identity: &Option<OwnUserIdentityData>,
973 device_owner_identity: &Option<UserIdentityData>,
974) -> Option<WithheldCode> {
975 match (
976 device_data.local_trust_state(),
977 device_data.is_cross_signing_trusted(own_identity, device_owner_identity),
978 ) {
979 (LocalTrust::BlackListed, _) => Some(WithheldCode::Blacklisted),
980 (LocalTrust::Ignored | LocalTrust::Verified, _) => None,
981 (LocalTrust::Unset, false) => Some(WithheldCode::Unverified),
982 (LocalTrust::Unset, true) => None,
983 }
984}
985
986fn is_unsigned_device_of_verified_user(
987 own_identity: Option<&OwnUserIdentityData>,
988 device_owner_identity: Option<&UserIdentityData>,
989 device_data: &DeviceData,
990) -> bool {
991 device_owner_identity.is_some_and(|device_owner_identity| {
992 is_user_verified(own_identity, device_owner_identity)
993 && !device_data.is_cross_signed_by_owner(device_owner_identity)
994 })
995}
996
997fn has_identity_verification_violation(
1004 own_identity: Option<&OwnUserIdentityData>,
1005 device_owner_identity: Option<&UserIdentityData>,
1006) -> bool {
1007 device_owner_identity.is_some_and(|device_owner_identity| {
1008 device_owner_identity.was_previously_verified()
1009 && !is_user_verified(own_identity, device_owner_identity)
1010 })
1011}
1012
1013fn is_user_verified(
1014 own_identity: Option<&OwnUserIdentityData>,
1015 user_identity: &UserIdentityData,
1016) -> bool {
1017 match user_identity {
1018 UserIdentityData::Own(own_identity) => own_identity.is_verified(),
1019 UserIdentityData::Other(other_identity) => {
1020 own_identity.is_some_and(|oi| oi.is_identity_verified(other_identity))
1021 }
1022 }
1023}
1024
1025#[cfg(test)]
1026mod tests {
1027 use std::{collections::BTreeMap, iter, ops::Deref, sync::Arc};
1028
1029 use assert_matches::assert_matches;
1030 use assert_matches2::assert_let;
1031 use insta::{assert_snapshot, with_settings};
1032 use matrix_sdk_common::deserialized_responses::WithheldCode;
1033 use matrix_sdk_test::{
1034 async_test, test_json,
1035 test_json::keys_query_sets::{
1036 IdentityChangeDataSet, KeyDistributionTestData, MaloIdentityChangeDataSet,
1037 VerificationViolationTestData,
1038 },
1039 };
1040 use ruma::{
1041 DeviceId, TransactionId, UserId, device_id,
1042 events::{dummy::ToDeviceDummyEventContent, room::history_visibility::HistoryVisibility},
1043 room_id,
1044 };
1045 use serde_json::json;
1046
1047 #[cfg(feature = "experimental-send-custom-to-device")]
1048 use super::split_devices_for_share_strategy;
1049 use crate::{
1050 CrossSigningKeyExport, DeviceData, EncryptionSettings, LocalTrust, OlmError, OlmMachine,
1051 error::SessionRecipientCollectionError,
1052 olm::{OutboundGroupSession, ShareInfo},
1053 session_manager::{
1054 CollectStrategy,
1055 group_sessions::share_strategy::{
1056 collect_session_recipients, withheld_code_for_device_for_share_strategy,
1057 },
1058 },
1059 store::caches::SequenceNumber,
1060 testing::simulate_key_query_response_for_verification,
1061 types::requests::ToDeviceRequest,
1062 };
1063
1064 async fn test_machine() -> OlmMachine {
1068 use KeyDistributionTestData as DataSet;
1069
1070 let machine = OlmMachine::new(DataSet::me_id(), DataSet::me_device_id()).await;
1072 let keys_query = DataSet::me_keys_query_response();
1073 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1074
1075 machine
1077 .import_cross_signing_keys(CrossSigningKeyExport {
1078 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1079 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1080 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1081 })
1082 .await
1083 .unwrap();
1084
1085 machine
1086 }
1087
1088 async fn get_device_data(
1090 machine: &OlmMachine,
1091 user_id: &UserId,
1092 device_id: &DeviceId,
1093 ) -> DeviceData {
1094 machine.get_device(user_id, device_id, None).await.unwrap().unwrap().deref().clone()
1095 }
1096
1097 async fn get_own_identity_data(
1098 machine: &OlmMachine,
1099 user_id: &UserId,
1100 ) -> Option<crate::OwnUserIdentityData> {
1101 machine
1102 .get_identity(user_id, None)
1103 .await
1104 .unwrap()
1105 .and_then(|i| i.own())
1106 .map(|i| i.deref().clone())
1107 }
1108
1109 async fn get_user_identity_data(
1110 machine: &OlmMachine,
1111 user_id: &UserId,
1112 ) -> Option<crate::UserIdentityData> {
1113 use crate::{UserIdentity, identities::user::UserIdentityData};
1114 machine.get_identity(user_id, None).await.unwrap().map(|i| match i {
1115 UserIdentity::Own(i) => UserIdentityData::Own(i.deref().clone()),
1116 UserIdentity::Other(i) => UserIdentityData::Other(i.deref().clone()),
1117 })
1118 }
1119
1120 async fn import_known_users_to_test_machine(machine: &OlmMachine) {
1123 let keys_query = KeyDistributionTestData::dan_keys_query_response();
1124 let txn_id = TransactionId::new();
1125 machine.mark_request_as_sent(&txn_id, &keys_query).await.unwrap();
1126
1127 let txn_id_dave = TransactionId::new();
1128 let keys_query_dave = KeyDistributionTestData::dave_keys_query_response();
1129 machine.mark_request_as_sent(&txn_id_dave, &keys_query_dave).await.unwrap();
1130
1131 let txn_id_good = TransactionId::new();
1132 let keys_query_good = KeyDistributionTestData::good_keys_query_response();
1133 machine.mark_request_as_sent(&txn_id_good, &keys_query_good).await.unwrap();
1134 }
1135
1136 #[test]
1139 #[cfg(not(feature = "experimental-encrypted-state-events"))]
1140 fn test_serialize_device_based_strategy() {
1141 let encryption_settings = all_devices_strategy_settings();
1142 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1143 with_settings!({prepend_module_to_snapshot => false}, {
1144 assert_snapshot!(serialized)
1145 });
1146 }
1147
1148 #[test]
1152 #[cfg(feature = "experimental-encrypted-state-events")]
1153 fn test_serialize_strategy_with_encrypted_state() {
1154 let encryption_settings = all_devices_strategy_settings();
1155 let serialized = serde_json::to_string(&encryption_settings).unwrap();
1156 with_settings!({prepend_module_to_snapshot => false}, {
1157 assert_snapshot!(serialized)
1158 });
1159 }
1160
1161 #[test]
1165 fn test_deserialize_old_device_based_strategy() {
1166 let settings: EncryptionSettings = serde_json::from_value(json!({
1167 "algorithm": "m.megolm.v1.aes-sha2",
1168 "rotation_period":{"secs":604800,"nanos":0},
1169 "rotation_period_msgs":100,
1170 "history_visibility":"shared",
1171 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":false}},
1172 })).unwrap();
1173 assert_matches!(settings.sharing_strategy, CollectStrategy::AllDevices);
1174 }
1175
1176 #[test]
1180 fn test_deserialize_old_error_on_verified_user_problem() {
1181 let settings: EncryptionSettings = serde_json::from_value(json!({
1182 "algorithm": "m.megolm.v1.aes-sha2",
1183 "rotation_period":{"secs":604800,"nanos":0},
1184 "rotation_period_msgs":100,
1185 "history_visibility":"shared",
1186 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":false,"error_on_verified_user_problem":true}},
1187 })).unwrap();
1188 assert_matches!(settings.sharing_strategy, CollectStrategy::ErrorOnVerifiedUserProblem);
1189 }
1190
1191 #[test]
1195 fn test_deserialize_old_only_trusted_devices_strategy() {
1196 let settings: EncryptionSettings = serde_json::from_value(json!({
1197 "algorithm": "m.megolm.v1.aes-sha2",
1198 "rotation_period":{"secs":604800,"nanos":0},
1199 "rotation_period_msgs":100,
1200 "history_visibility":"shared",
1201 "sharing_strategy":{"DeviceBasedStrategy":{"only_allow_trusted_devices":true,"error_on_verified_user_problem":false}},
1202 })).unwrap();
1203 assert_matches!(settings.sharing_strategy, CollectStrategy::OnlyTrustedDevices);
1204 }
1205
1206 #[async_test]
1207 async fn test_share_with_per_device_strategy_to_all() {
1208 let machine = test_machine().await;
1209 import_known_users_to_test_machine(&machine).await;
1210
1211 let encryption_settings = all_devices_strategy_settings();
1212
1213 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1214
1215 let share_result = collect_session_recipients(
1216 machine.store(),
1217 vec![
1218 KeyDistributionTestData::dan_id(),
1219 KeyDistributionTestData::dave_id(),
1220 KeyDistributionTestData::good_id(),
1221 ]
1222 .into_iter(),
1223 &encryption_settings,
1224 &group_session,
1225 )
1226 .await
1227 .unwrap();
1228
1229 assert!(!share_result.should_rotate);
1230
1231 let dan_devices_shared =
1232 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1233 let dave_devices_shared =
1234 share_result.devices.get(KeyDistributionTestData::dave_id()).unwrap();
1235 let good_devices_shared =
1236 share_result.devices.get(KeyDistributionTestData::good_id()).unwrap();
1237
1238 assert_eq!(dan_devices_shared.len(), 2);
1240 assert_eq!(dave_devices_shared.len(), 1);
1241 assert_eq!(good_devices_shared.len(), 2);
1242
1243 #[cfg(feature = "experimental-send-custom-to-device")]
1244 {
1245 let mut all_devices = dan_devices_shared.clone();
1249 all_devices.append(&mut dave_devices_shared.clone());
1250 all_devices.append(&mut good_devices_shared.clone());
1251
1252 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1253 machine.store(),
1254 all_devices,
1255 CollectStrategy::AllDevices,
1256 )
1257 .await
1258 .unwrap();
1259
1260 assert_eq!(shared_devices.len(), 5);
1261 assert_eq!(withheld_devices.len(), 0);
1262 }
1263
1264 let own_identity_data =
1265 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1266 let dan_identity_data =
1267 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1268
1269 assert_eq!(
1270 withheld_code_for_device_for_share_strategy(
1271 &get_device_data(
1272 &machine,
1273 KeyDistributionTestData::dan_id(),
1274 KeyDistributionTestData::dan_signed_device_id()
1275 )
1276 .await,
1277 CollectStrategy::AllDevices,
1278 &own_identity_data,
1279 &dan_identity_data,
1280 )
1281 .await
1282 .unwrap(),
1283 None,
1284 );
1285 }
1286
1287 #[async_test]
1288 async fn test_share_with_only_trusted_strategy() {
1289 let machine = test_machine().await;
1290 import_known_users_to_test_machine(&machine).await;
1291
1292 let encryption_settings = EncryptionSettings {
1293 sharing_strategy: CollectStrategy::OnlyTrustedDevices,
1294 ..Default::default()
1295 };
1296
1297 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1298
1299 let share_result = collect_session_recipients(
1300 machine.store(),
1301 vec![
1302 KeyDistributionTestData::dan_id(),
1303 KeyDistributionTestData::dave_id(),
1304 KeyDistributionTestData::good_id(),
1305 ]
1306 .into_iter(),
1307 &encryption_settings,
1308 &group_session,
1309 )
1310 .await
1311 .unwrap();
1312
1313 assert!(!share_result.should_rotate);
1314
1315 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
1316 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
1317 assert!(dave_devices_shared.unwrap().is_empty());
1319 assert!(good_devices_shared.unwrap().is_empty());
1320
1321 let dan_devices_shared =
1324 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
1325
1326 assert_eq!(dan_devices_shared.len(), 1);
1327 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
1328 assert_eq!(
1329 dan_device_that_will_get_the_key.device_id().as_str(),
1330 KeyDistributionTestData::dan_signed_device_id()
1331 );
1332
1333 let (_, code) = share_result
1335 .withheld_devices
1336 .iter()
1337 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
1338 .expect("This dan's device should receive a withheld code");
1339
1340 assert_eq!(code, &WithheldCode::Unverified);
1341
1342 let (_, code) = share_result
1343 .withheld_devices
1344 .iter()
1345 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
1346 .expect("This daves's device should receive a withheld code");
1347
1348 assert_eq!(code, &WithheldCode::Unverified);
1349
1350 #[cfg(feature = "experimental-send-custom-to-device")]
1351 {
1352 let all_devices: Vec<DeviceData> = vec![
1353 get_device_data(
1354 &machine,
1355 KeyDistributionTestData::dan_id(),
1356 KeyDistributionTestData::dan_unsigned_device_id(),
1357 )
1358 .await,
1359 get_device_data(
1360 &machine,
1361 KeyDistributionTestData::dan_id(),
1362 KeyDistributionTestData::dan_signed_device_id(),
1363 )
1364 .await,
1365 get_device_data(
1366 &machine,
1367 KeyDistributionTestData::dave_id(),
1368 KeyDistributionTestData::dave_device_id(),
1369 )
1370 .await,
1371 get_device_data(
1372 &machine,
1373 KeyDistributionTestData::good_id(),
1374 KeyDistributionTestData::good_device_1_id(),
1375 )
1376 .await,
1377 get_device_data(
1378 &machine,
1379 KeyDistributionTestData::good_id(),
1380 KeyDistributionTestData::good_device_2_id(),
1381 )
1382 .await,
1383 ];
1384
1385 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1386 machine.store(),
1387 all_devices,
1388 CollectStrategy::OnlyTrustedDevices,
1389 )
1390 .await
1391 .unwrap();
1392
1393 assert_eq!(shared_devices.len(), 1);
1394 assert_eq!(
1395 shared_devices[0].device_id().as_str(),
1396 KeyDistributionTestData::dan_signed_device_id()
1397 );
1398
1399 assert_eq!(withheld_devices.len(), 4);
1400 assert_eq!(
1401 withheld_devices[0].0.device_id().as_str(),
1402 KeyDistributionTestData::dan_unsigned_device_id()
1403 );
1404 assert_eq!(withheld_devices[0].1, WithheldCode::Unverified);
1405 assert_eq!(
1406 withheld_devices[1].0.device_id().as_str(),
1407 KeyDistributionTestData::dave_device_id()
1408 );
1409 assert_eq!(withheld_devices[1].1, WithheldCode::Unverified);
1410 }
1411
1412 let own_identity_data =
1413 get_own_identity_data(&machine, KeyDistributionTestData::me_id()).await;
1414 let dan_identity_data =
1415 get_user_identity_data(&machine, KeyDistributionTestData::dan_id()).await;
1416 let dave_identity_data =
1417 get_user_identity_data(&machine, KeyDistributionTestData::dave_id()).await;
1418
1419 assert_eq!(
1420 withheld_code_for_device_for_share_strategy(
1421 &get_device_data(
1422 &machine,
1423 KeyDistributionTestData::dan_id(),
1424 KeyDistributionTestData::dan_signed_device_id()
1425 )
1426 .await,
1427 CollectStrategy::OnlyTrustedDevices,
1428 &own_identity_data,
1429 &dan_identity_data,
1430 )
1431 .await
1432 .unwrap(),
1433 None,
1434 );
1435 assert_eq!(
1436 withheld_code_for_device_for_share_strategy(
1437 &get_device_data(
1438 &machine,
1439 KeyDistributionTestData::dan_id(),
1440 KeyDistributionTestData::dan_unsigned_device_id()
1441 )
1442 .await,
1443 CollectStrategy::OnlyTrustedDevices,
1444 &own_identity_data,
1445 &dan_identity_data,
1446 )
1447 .await
1448 .unwrap(),
1449 Some(WithheldCode::Unverified),
1450 );
1451 assert_eq!(
1452 withheld_code_for_device_for_share_strategy(
1453 &get_device_data(
1454 &machine,
1455 KeyDistributionTestData::dave_id(),
1456 KeyDistributionTestData::dave_device_id()
1457 )
1458 .await,
1459 CollectStrategy::OnlyTrustedDevices,
1460 &own_identity_data,
1461 &dave_identity_data,
1462 )
1463 .await
1464 .unwrap(),
1465 Some(WithheldCode::Unverified),
1466 );
1467 }
1468
1469 #[async_test]
1473 async fn test_error_on_unsigned_of_verified_users() {
1474 use VerificationViolationTestData as DataSet;
1475
1476 let machine = unsigned_of_verified_setup().await;
1478
1479 let carol_keys = DataSet::carol_keys_query_response_signed();
1481 machine.mark_request_as_sent(&TransactionId::new(), &carol_keys).await.unwrap();
1482
1483 let carol_identity =
1485 machine.get_identity(DataSet::carol_id(), None).await.unwrap().unwrap();
1486 assert!(carol_identity.other().unwrap().is_verified());
1487
1488 let carol_unsigned_device = machine
1489 .get_device(DataSet::carol_id(), DataSet::carol_unsigned_device_id(), None)
1490 .await
1491 .unwrap()
1492 .unwrap();
1493 assert!(!carol_unsigned_device.is_verified());
1494
1495 let encryption_settings = error_on_verification_problem_encryption_settings();
1497 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1498 let share_result = collect_session_recipients(
1499 machine.store(),
1500 vec![DataSet::bob_id(), DataSet::carol_id()].into_iter(),
1501 &encryption_settings,
1502 &group_session,
1503 )
1504 .await;
1505
1506 assert_let!(
1507 Err(OlmError::SessionRecipientCollectionError(
1508 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1509 )) = share_result
1510 );
1511
1512 assert_eq!(
1514 unverified_devices,
1515 BTreeMap::from([
1516 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1517 (
1518 DataSet::carol_id().to_owned(),
1519 vec![DataSet::carol_unsigned_device_id().to_owned()]
1520 ),
1521 ])
1522 );
1523
1524 #[cfg(feature = "experimental-send-custom-to-device")]
1525 {
1526 let all_devices = vec![
1527 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1528 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1529 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1530 .await,
1531 get_device_data(&machine, DataSet::carol_id(), DataSet::carol_unsigned_device_id())
1532 .await,
1533 ];
1534
1535 let split_result = split_devices_for_share_strategy(
1536 machine.store(),
1537 all_devices,
1538 CollectStrategy::ErrorOnVerifiedUserProblem,
1539 )
1540 .await;
1541
1542 assert_let!(
1543 Err(OlmError::SessionRecipientCollectionError(
1544 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1545 unverified_devices
1546 )
1547 )) = split_result
1548 );
1549
1550 assert_eq!(
1552 unverified_devices,
1553 BTreeMap::from([
1554 (DataSet::bob_id().to_owned(), vec![DataSet::bob_device_2_id().to_owned()]),
1555 (
1556 DataSet::carol_id().to_owned(),
1557 vec![DataSet::carol_unsigned_device_id().to_owned()]
1558 ),
1559 ])
1560 );
1561 }
1562
1563 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1564 let carol_identity_data = get_user_identity_data(&machine, DataSet::carol_id()).await;
1565
1566 assert_eq!(
1567 withheld_code_for_device_for_share_strategy(
1568 &get_device_data(&machine, DataSet::carol_id(), DataSet::carol_signed_device_id())
1569 .await,
1570 CollectStrategy::ErrorOnVerifiedUserProblem,
1571 &own_identity_data,
1572 &carol_identity_data,
1573 )
1574 .await
1575 .unwrap(),
1576 None,
1577 );
1578 assert_let!(
1579 Err(OlmError::SessionRecipientCollectionError(
1580 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1581 )) = withheld_code_for_device_for_share_strategy(
1582 &get_device_data(
1583 &machine,
1584 DataSet::carol_id(),
1585 DataSet::carol_unsigned_device_id()
1586 )
1587 .await,
1588 CollectStrategy::ErrorOnVerifiedUserProblem,
1589 &own_identity_data,
1590 &carol_identity_data,
1591 )
1592 .await
1593 );
1594 }
1595
1596 #[async_test]
1600 async fn test_error_on_unsigned_of_verified_resolve_by_whitelisting() {
1601 use VerificationViolationTestData as DataSet;
1602
1603 let machine = unsigned_of_verified_setup().await;
1604
1605 machine
1607 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1608 .await
1609 .unwrap()
1610 .unwrap()
1611 .set_local_trust(LocalTrust::Ignored)
1612 .await
1613 .unwrap();
1614
1615 let encryption_settings = error_on_verification_problem_encryption_settings();
1616 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1617
1618 let share_result = collect_session_recipients(
1620 machine.store(),
1621 iter::once(DataSet::bob_id()),
1622 &encryption_settings,
1623 &group_session,
1624 )
1625 .await
1626 .unwrap();
1627
1628 assert_eq!(2, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1629 assert_eq!(0, share_result.withheld_devices.len());
1630
1631 #[cfg(feature = "experimental-send-custom-to-device")]
1632 {
1633 let all_devices = vec![
1634 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1635 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1636 ];
1637
1638 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1639 machine.store(),
1640 all_devices,
1641 CollectStrategy::ErrorOnVerifiedUserProblem,
1642 )
1643 .await
1644 .unwrap();
1645
1646 assert_eq!(shared_devices.len(), 2);
1647 assert_eq!(withheld_devices.len(), 0);
1648 }
1649
1650 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1651 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1652
1653 assert_eq!(
1654 withheld_code_for_device_for_share_strategy(
1655 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1656 CollectStrategy::ErrorOnVerifiedUserProblem,
1657 &own_identity_data,
1658 &bob_identity_data,
1659 )
1660 .await
1661 .unwrap(),
1662 None,
1663 );
1664 }
1665
1666 #[async_test]
1670 async fn test_error_on_unsigned_of_verified_resolve_by_blacklisting() {
1671 use VerificationViolationTestData as DataSet;
1672
1673 let machine = unsigned_of_verified_setup().await;
1674
1675 machine
1677 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1678 .await
1679 .unwrap()
1680 .unwrap()
1681 .set_local_trust(LocalTrust::BlackListed)
1682 .await
1683 .unwrap();
1684
1685 let encryption_settings = error_on_verification_problem_encryption_settings();
1686 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1687
1688 let share_result = collect_session_recipients(
1690 machine.store(),
1691 iter::once(DataSet::bob_id()),
1692 &encryption_settings,
1693 &group_session,
1694 )
1695 .await
1696 .unwrap();
1697
1698 assert_eq!(1, share_result.devices.get(DataSet::bob_id()).unwrap().len());
1699 let withheld_list: Vec<_> = share_result
1700 .withheld_devices
1701 .iter()
1702 .map(|(d, code)| (d.device_id().to_owned(), code.clone()))
1703 .collect();
1704 assert_eq!(
1705 withheld_list,
1706 vec![(DataSet::bob_device_2_id().to_owned(), WithheldCode::Blacklisted)]
1707 );
1708
1709 let bob_device_2 =
1710 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await;
1711 #[cfg(feature = "experimental-send-custom-to-device")]
1712 {
1713 let bob_device_1 =
1714 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await;
1715 let all_devices = vec![bob_device_1.clone(), bob_device_2.clone()];
1716
1717 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1718 machine.store(),
1719 all_devices,
1720 CollectStrategy::ErrorOnVerifiedUserProblem,
1721 )
1722 .await
1723 .unwrap();
1724
1725 assert_eq!(shared_devices, vec![bob_device_1.clone()]);
1726 assert_eq!(withheld_devices, vec![(bob_device_2.clone(), WithheldCode::Blacklisted)]);
1727 }
1728
1729 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1730 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1731
1732 assert_eq!(
1733 withheld_code_for_device_for_share_strategy(
1734 &bob_device_2,
1735 CollectStrategy::ErrorOnVerifiedUserProblem,
1736 &own_identity_data,
1737 &bob_identity_data,
1738 )
1739 .await
1740 .unwrap(),
1741 Some(WithheldCode::Blacklisted),
1742 );
1743 }
1744
1745 #[async_test]
1749 async fn test_error_on_unsigned_of_verified_owner_is_us() {
1750 use VerificationViolationTestData as DataSet;
1751
1752 let machine = unsigned_of_verified_setup().await;
1753
1754 let mut own_keys = DataSet::own_keys_query_response_1().clone();
1756 own_keys.device_keys.insert(
1757 DataSet::own_id().to_owned(),
1758 BTreeMap::from([
1759 DataSet::own_signed_device_keys(),
1760 DataSet::own_unsigned_device_keys(),
1761 ]),
1762 );
1763 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1764
1765 let encryption_settings = error_on_verification_problem_encryption_settings();
1766 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1767 let share_result = collect_session_recipients(
1768 machine.store(),
1769 iter::once(DataSet::own_id()),
1770 &encryption_settings,
1771 &group_session,
1772 )
1773 .await;
1774
1775 assert_let!(
1776 Err(OlmError::SessionRecipientCollectionError(
1777 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(unverified_devices)
1778 )) = share_result
1779 );
1780
1781 assert_eq!(
1783 unverified_devices,
1784 BTreeMap::from([(
1785 DataSet::own_id().to_owned(),
1786 vec![DataSet::own_unsigned_device_id()]
1787 ),])
1788 );
1789
1790 #[cfg(feature = "experimental-send-custom-to-device")]
1791 {
1792 let all_devices = vec![
1793 get_device_data(&machine, DataSet::own_id(), &DataSet::own_signed_device_id())
1794 .await,
1795 get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1796 .await,
1797 ];
1798
1799 let split_result = split_devices_for_share_strategy(
1800 machine.store(),
1801 all_devices,
1802 CollectStrategy::ErrorOnVerifiedUserProblem,
1803 )
1804 .await;
1805 assert_let!(
1806 Err(OlmError::SessionRecipientCollectionError(
1807 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(
1808 unverified_devices
1809 )
1810 )) = split_result
1811 );
1812
1813 assert_eq!(
1815 unverified_devices,
1816 BTreeMap::from([(
1817 DataSet::own_id().to_owned(),
1818 vec![DataSet::own_unsigned_device_id()]
1819 ),])
1820 );
1821 }
1822
1823 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1824 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
1825
1826 assert_let!(
1827 Err(OlmError::SessionRecipientCollectionError(
1828 SessionRecipientCollectionError::VerifiedUserHasUnsignedDevice(_)
1829 )) = withheld_code_for_device_for_share_strategy(
1830 &get_device_data(&machine, DataSet::own_id(), &DataSet::own_unsigned_device_id())
1831 .await,
1832 CollectStrategy::ErrorOnVerifiedUserProblem,
1833 &own_identity_data,
1834 &own_user_identity_data,
1835 )
1836 .await
1837 );
1838 }
1839
1840 #[async_test]
1843 async fn test_should_not_error_on_unsigned_of_unverified() {
1844 use VerificationViolationTestData as DataSet;
1845
1846 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1847
1848 let own_keys = DataSet::own_keys_query_response_1();
1850 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
1851
1852 machine
1854 .import_cross_signing_keys(CrossSigningKeyExport {
1855 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
1856 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1857 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
1858 })
1859 .await
1860 .unwrap();
1861
1862 let bob_keys = DataSet::bob_keys_query_response_rotated();
1864 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
1865
1866 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
1869 assert!(!bob_identity.other().unwrap().is_verified());
1870
1871 let bob_unsigned_device = machine
1872 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
1873 .await
1874 .unwrap()
1875 .unwrap();
1876 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1877
1878 let encryption_settings = error_on_verification_problem_encryption_settings();
1879 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1880 collect_session_recipients(
1881 machine.store(),
1882 iter::once(DataSet::bob_id()),
1883 &encryption_settings,
1884 &group_session,
1885 )
1886 .await
1887 .unwrap();
1888
1889 #[cfg(feature = "experimental-send-custom-to-device")]
1890 {
1891 let all_devices = vec![
1892 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1893 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1894 ];
1895
1896 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1897 machine.store(),
1898 all_devices,
1899 CollectStrategy::ErrorOnVerifiedUserProblem,
1900 )
1901 .await
1902 .unwrap();
1903
1904 assert_eq!(shared_devices.len(), 2);
1905 assert_eq!(withheld_devices.len(), 0);
1906 }
1907
1908 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1909 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1910
1911 assert_eq!(
1912 withheld_code_for_device_for_share_strategy(
1913 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1914 CollectStrategy::ErrorOnVerifiedUserProblem,
1915 &own_identity_data,
1916 &bob_identity_data,
1917 )
1918 .await
1919 .unwrap(),
1920 None,
1921 );
1922 }
1923
1924 #[async_test]
1927 async fn test_should_not_error_on_unsigned_of_signed_but_unverified() {
1928 use VerificationViolationTestData as DataSet;
1929
1930 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
1931
1932 let keys_query = DataSet::own_keys_query_response_1();
1934 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1935
1936 let keys_query = DataSet::bob_keys_query_response_signed();
1938 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
1939
1940 let bob_identity =
1943 machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap().other().unwrap();
1944 assert!(
1945 bob_identity.own_identity.as_ref().unwrap().is_identity_signed(&bob_identity.inner)
1946 );
1947 assert!(!bob_identity.is_verified());
1948
1949 let bob_unsigned_device = machine
1950 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
1951 .await
1952 .unwrap()
1953 .unwrap();
1954 assert!(!bob_unsigned_device.is_cross_signed_by_owner());
1955
1956 let encryption_settings = error_on_verification_problem_encryption_settings();
1958 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
1959 collect_session_recipients(
1960 machine.store(),
1961 iter::once(DataSet::bob_id()),
1962 &encryption_settings,
1963 &group_session,
1964 )
1965 .await
1966 .unwrap();
1967
1968 #[cfg(feature = "experimental-send-custom-to-device")]
1969 {
1970 let all_devices = vec![
1971 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
1972 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1973 ];
1974
1975 let (shared_devices, withheld_devices) = split_devices_for_share_strategy(
1976 machine.store(),
1977 all_devices,
1978 CollectStrategy::ErrorOnVerifiedUserProblem,
1979 )
1980 .await
1981 .unwrap();
1982
1983 assert_eq!(shared_devices.len(), 2);
1984 assert_eq!(withheld_devices.len(), 0);
1985 }
1986
1987 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
1988 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
1989
1990 assert_eq!(
1991 withheld_code_for_device_for_share_strategy(
1992 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
1993 CollectStrategy::ErrorOnVerifiedUserProblem,
1994 &own_identity_data,
1995 &bob_identity_data,
1996 )
1997 .await
1998 .unwrap(),
1999 None,
2000 );
2001 }
2002
2003 #[async_test]
2007 async fn test_verified_user_changed_identity() {
2008 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2009
2010 let machine = unsigned_of_verified_setup().await;
2013
2014 let bob_keys = DataSet::bob_keys_query_response_rotated();
2016 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
2017
2018 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
2020 assert!(bob_identity.has_verification_violation());
2021
2022 let encryption_settings = error_on_verification_problem_encryption_settings();
2024 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2025 let share_result = collect_session_recipients(
2026 machine.store(),
2027 iter::once(DataSet::bob_id()),
2028 &encryption_settings,
2029 &group_session,
2030 )
2031 .await;
2032
2033 assert_let!(
2034 Err(OlmError::SessionRecipientCollectionError(
2035 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2036 )) = share_result
2037 );
2038 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2039
2040 #[cfg(feature = "experimental-send-custom-to-device")]
2041 {
2042 let all_devices = vec![
2043 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2044 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2045 ];
2046
2047 let split_result = split_devices_for_share_strategy(
2048 machine.store(),
2049 all_devices,
2050 CollectStrategy::ErrorOnVerifiedUserProblem,
2051 )
2052 .await;
2053 assert_let!(
2054 Err(OlmError::SessionRecipientCollectionError(
2055 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2056 )) = split_result
2057 );
2058 assert_eq!(violating_users, vec![DataSet::bob_id()]);
2059 }
2060
2061 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2062 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2063
2064 assert_let!(
2065 Err(OlmError::SessionRecipientCollectionError(
2066 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2067 )) = withheld_code_for_device_for_share_strategy(
2068 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2069 CollectStrategy::ErrorOnVerifiedUserProblem,
2070 &own_identity_data,
2071 &bob_identity_data,
2072 )
2073 .await
2074 );
2075
2076 bob_identity.withdraw_verification().await.unwrap();
2078
2079 collect_session_recipients(
2080 machine.store(),
2081 iter::once(DataSet::bob_id()),
2082 &encryption_settings,
2083 &group_session,
2084 )
2085 .await
2086 .unwrap();
2087
2088 #[cfg(feature = "experimental-send-custom-to-device")]
2089 {
2090 let all_devices = vec![
2091 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2092 get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_2_id()).await,
2093 ];
2094
2095 split_devices_for_share_strategy(
2096 machine.store(),
2097 all_devices,
2098 CollectStrategy::ErrorOnVerifiedUserProblem,
2099 )
2100 .await
2101 .unwrap();
2102 }
2103
2104 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2105 let bob_identity_data = get_user_identity_data(&machine, DataSet::bob_id()).await;
2106
2107 assert_eq!(
2108 withheld_code_for_device_for_share_strategy(
2109 &get_device_data(&machine, DataSet::bob_id(), DataSet::bob_device_1_id()).await,
2110 CollectStrategy::ErrorOnVerifiedUserProblem,
2111 &own_identity_data,
2112 &bob_identity_data,
2113 )
2114 .await
2115 .unwrap(),
2116 None,
2117 );
2118 }
2119
2120 #[async_test]
2124 async fn test_own_verified_identity_changed() {
2125 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
2126
2127 let machine = unsigned_of_verified_setup().await;
2129 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2130 assert!(own_identity.own().unwrap().is_verified());
2131
2132 let own_keys = DataSet::own_keys_query_response_2();
2134 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
2135
2136 let own_identity = machine.get_identity(DataSet::own_id(), None).await.unwrap().unwrap();
2137 assert!(!own_identity.is_verified());
2138
2139 let encryption_settings = error_on_verification_problem_encryption_settings();
2141 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2142 let share_result = collect_session_recipients(
2143 machine.store(),
2144 iter::once(DataSet::own_id()),
2145 &encryption_settings,
2146 &group_session,
2147 )
2148 .await;
2149
2150 assert_let!(
2151 Err(OlmError::SessionRecipientCollectionError(
2152 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2153 )) = share_result
2154 );
2155 assert_eq!(violating_users, vec![DataSet::own_id()]);
2156
2157 #[cfg(feature = "experimental-send-custom-to-device")]
2158 {
2159 let all_devices: Vec<DeviceData> =
2160 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2161
2162 let split_result = split_devices_for_share_strategy(
2163 machine.store(),
2164 all_devices,
2165 CollectStrategy::ErrorOnVerifiedUserProblem,
2166 )
2167 .await;
2168
2169 assert_let!(
2170 Err(OlmError::SessionRecipientCollectionError(
2171 SessionRecipientCollectionError::VerifiedUserChangedIdentity(violating_users)
2172 )) = split_result
2173 );
2174 assert_eq!(violating_users, vec![DataSet::own_id()]);
2175 }
2176
2177 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2178 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2179
2180 assert_let!(
2181 Err(OlmError::SessionRecipientCollectionError(
2182 SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2183 )) = withheld_code_for_device_for_share_strategy(
2184 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2185 CollectStrategy::ErrorOnVerifiedUserProblem,
2186 &own_identity_data,
2187 &own_user_identity_data,
2188 )
2189 .await
2190 );
2191
2192 own_identity.withdraw_verification().await.unwrap();
2194
2195 collect_session_recipients(
2196 machine.store(),
2197 iter::once(DataSet::own_id()),
2198 &encryption_settings,
2199 &group_session,
2200 )
2201 .await
2202 .unwrap();
2203
2204 #[cfg(feature = "experimental-send-custom-to-device")]
2205 {
2206 let all_devices: Vec<DeviceData> =
2207 vec![get_device_data(&machine, DataSet::own_id(), machine.device_id()).await];
2208
2209 split_devices_for_share_strategy(
2210 machine.store(),
2211 all_devices,
2212 CollectStrategy::ErrorOnVerifiedUserProblem,
2213 )
2214 .await
2215 .unwrap();
2216 }
2217
2218 let own_identity_data = get_own_identity_data(&machine, DataSet::own_id()).await;
2219 let own_user_identity_data = get_user_identity_data(&machine, DataSet::own_id()).await;
2220
2221 withheld_code_for_device_for_share_strategy(
2222 &get_device_data(&machine, DataSet::own_id(), machine.device_id()).await,
2223 CollectStrategy::ErrorOnVerifiedUserProblem,
2224 &own_identity_data,
2225 &own_user_identity_data,
2226 )
2227 .await
2228 .unwrap();
2229 }
2230
2231 mod dehydrated_device {
2234 use std::{collections::HashSet, iter};
2235
2236 use insta::{allow_duplicates, assert_json_snapshot, with_settings};
2237 use matrix_sdk_common::deserialized_responses::WithheldCode;
2238 use matrix_sdk_test::{
2239 async_test, ruma_response_to_json,
2240 test_json::keys_query_sets::{
2241 KeyDistributionTestData, KeyQueryResponseTemplate,
2242 KeyQueryResponseTemplateDeviceOptions,
2243 },
2244 };
2245 use ruma::{DeviceId, TransactionId, UserId, device_id, user_id};
2246 use vodozemac::{Curve25519PublicKey, Ed25519SecretKey};
2247
2248 use super::{
2249 all_devices_strategy_settings, create_test_outbound_group_session,
2250 error_on_verification_problem_encryption_settings, identity_based_strategy_settings,
2251 test_machine,
2252 };
2253 use crate::{
2254 EncryptionSettings, OlmMachine,
2255 session_manager::group_sessions::{
2256 CollectRecipientsResult, share_strategy::collect_session_recipients,
2257 },
2258 };
2259
2260 #[async_test]
2261 async fn test_all_devices_strategy_should_share_with_verified_dehydrated_device() {
2262 should_share_with_verified_dehydrated_device(&all_devices_strategy_settings()).await
2263 }
2264
2265 #[async_test]
2266 async fn test_error_on_verification_problem_strategy_should_share_with_verified_dehydrated_device()
2267 {
2268 should_share_with_verified_dehydrated_device(
2269 &error_on_verification_problem_encryption_settings(),
2270 )
2271 .await
2272 }
2273
2274 #[async_test]
2275 async fn test_identity_based_strategy_should_share_with_verified_dehydrated_device() {
2276 should_share_with_verified_dehydrated_device(&identity_based_strategy_settings()).await
2277 }
2278
2279 async fn should_share_with_verified_dehydrated_device(
2284 encryption_settings: &EncryptionSettings,
2285 ) {
2286 let machine = test_machine().await;
2287
2288 let bob_user_id = user_id!("@bob:localhost");
2291 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2292 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2293 .with_dehydrated_device(bob_dehydrated_device_id, true)
2294 .build_response();
2295 allow_duplicates! {
2296 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2297 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2298 });
2299 }
2300 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2301
2302 let recips = share_test_session_and_collect_recipients(
2304 &machine,
2305 bob_user_id,
2306 encryption_settings,
2307 )
2308 .await;
2309
2310 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2312 }
2313
2314 #[async_test]
2315 async fn test_all_devices_strategy_should_not_share_with_unverified_dehydrated_device() {
2316 should_not_share_with_unverified_dehydrated_device(&all_devices_strategy_settings())
2317 .await
2318 }
2319
2320 #[async_test]
2321 async fn test_error_on_verification_problem_strategy_should_not_share_with_unverified_dehydrated_device()
2322 {
2323 should_not_share_with_unverified_dehydrated_device(
2324 &error_on_verification_problem_encryption_settings(),
2325 )
2326 .await
2327 }
2328
2329 #[async_test]
2330 async fn test_identity_based_strategy_should_not_share_with_unverified_dehydrated_device() {
2331 should_not_share_with_unverified_dehydrated_device(&identity_based_strategy_settings())
2332 .await
2333 }
2334
2335 async fn should_not_share_with_unverified_dehydrated_device(
2340 encryption_settings: &EncryptionSettings,
2341 ) {
2342 let machine = test_machine().await;
2343
2344 let bob_user_id = user_id!("@bob:localhost");
2347 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2348 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2349 .with_dehydrated_device(bob_dehydrated_device_id, false)
2350 .build_response();
2351 allow_duplicates! {
2352 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2353 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2354 });
2355 }
2356 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2357
2358 let recips = share_test_session_and_collect_recipients(
2360 &machine,
2361 bob_user_id,
2362 encryption_settings,
2363 )
2364 .await;
2365
2366 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2369 }
2370
2371 #[async_test]
2372 async fn test_all_devices_strategy_should_share_with_verified_device_of_pin_violation_user()
2373 {
2374 should_share_with_verified_device_of_pin_violation_user(
2375 &all_devices_strategy_settings(),
2376 )
2377 .await
2378 }
2379
2380 #[async_test]
2381 async fn test_error_on_verification_problem_strategy_should_share_with_verified_device_of_pin_violation_user()
2382 {
2383 should_share_with_verified_device_of_pin_violation_user(
2384 &error_on_verification_problem_encryption_settings(),
2385 )
2386 .await
2387 }
2388
2389 #[async_test]
2390 async fn test_identity_based_strategy_should_share_with_verified_device_of_pin_violation_user()
2391 {
2392 should_share_with_verified_device_of_pin_violation_user(
2393 &identity_based_strategy_settings(),
2394 )
2395 .await
2396 }
2397
2398 async fn should_share_with_verified_device_of_pin_violation_user(
2403 encryption_settings: &EncryptionSettings,
2404 ) {
2405 let machine = test_machine().await;
2406
2407 let bob_user_id = user_id!("@bob:localhost");
2409 let keys_query =
2410 key_query_response_template_with_cross_signing(bob_user_id).build_response();
2411 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2412
2413 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2416 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2417 .with_dehydrated_device(bob_dehydrated_device_id, true)
2418 .build_response();
2419 allow_duplicates! {
2420 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2421 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2422 });
2423 }
2424 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2425
2426 let recips = share_test_session_and_collect_recipients(
2428 &machine,
2429 bob_user_id,
2430 encryption_settings,
2431 )
2432 .await;
2433
2434 assert_shared_with(recips, bob_user_id, [bob_dehydrated_device_id].into());
2436 }
2437
2438 #[async_test]
2439 async fn test_all_devices_strategy_should_not_share_with_dehydrated_device_of_verification_violation_user()
2440 {
2441 should_not_share_with_dehydrated_device_of_verification_violation_user(
2442 &all_devices_strategy_settings(),
2443 )
2444 .await
2445 }
2446
2447 async fn should_not_share_with_dehydrated_device_of_verification_violation_user(
2450 encryption_settings: &EncryptionSettings,
2451 ) {
2452 let bob_user_id = user_id!("@bob:localhost");
2453 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2454 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2455 bob_user_id,
2456 bob_dehydrated_device_id,
2457 )
2458 .await;
2459
2460 let recips = share_test_session_and_collect_recipients(
2462 &machine,
2463 bob_user_id,
2464 encryption_settings,
2465 )
2466 .await;
2467
2468 assert_withheld_to(recips, bob_user_id, bob_dehydrated_device_id);
2471 }
2472
2473 #[async_test]
2474 async fn test_error_on_verification_problem_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2475 {
2476 should_give_error_for_dehydrated_device_of_verification_violation_user(
2477 &error_on_verification_problem_encryption_settings(),
2478 )
2479 .await
2480 }
2481
2482 #[async_test]
2483 async fn test_identity_based_strategy_should_give_error_for_dehydrated_device_of_verification_violation_user()
2484 {
2485 should_give_error_for_dehydrated_device_of_verification_violation_user(
2489 &identity_based_strategy_settings(),
2490 )
2491 .await
2492 }
2493
2494 async fn should_give_error_for_dehydrated_device_of_verification_violation_user(
2498 encryption_settings: &EncryptionSettings,
2499 ) {
2500 let bob_user_id = user_id!("@bob:localhost");
2501 let bob_dehydrated_device_id = device_id!("DEHYDRATED_DEVICE");
2502 let machine = prepare_machine_with_dehydrated_device_of_verification_violation_user(
2503 bob_user_id,
2504 bob_dehydrated_device_id,
2505 )
2506 .await;
2507
2508 let group_session = create_test_outbound_group_session(&machine, encryption_settings);
2509 let share_result = collect_session_recipients(
2510 machine.store(),
2511 iter::once(bob_user_id),
2512 encryption_settings,
2513 &group_session,
2514 )
2515 .await;
2516
2517 assert_matches::assert_matches!(
2520 share_result,
2521 Err(crate::OlmError::SessionRecipientCollectionError(
2522 crate::SessionRecipientCollectionError::VerifiedUserChangedIdentity(_)
2523 ))
2524 );
2525 }
2526
2527 async fn prepare_machine_with_dehydrated_device_of_verification_violation_user(
2531 bob_user_id: &UserId,
2532 bob_dehydrated_device_id: &DeviceId,
2533 ) -> OlmMachine {
2534 let machine = test_machine().await;
2535
2536 let keys_query = key_query_response_template_with_cross_signing(bob_user_id)
2538 .with_user_verification_signature(
2539 KeyDistributionTestData::me_id(),
2540 &KeyDistributionTestData::me_private_user_signing_key(),
2541 )
2542 .build_response();
2543 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2544
2545 let keys_query = key_query_response_template_with_changed_cross_signing(bob_user_id)
2548 .with_dehydrated_device(bob_dehydrated_device_id, true)
2549 .build_response();
2550 allow_duplicates! {
2551 with_settings!({ sort_maps => true, prepend_module_to_snapshot => false }, {
2552 assert_json_snapshot!(ruma_response_to_json(keys_query.clone()))
2553 });
2554 }
2555 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2556
2557 machine
2558 }
2559
2560 async fn share_test_session_and_collect_recipients(
2563 machine: &OlmMachine,
2564 target_user_id: &UserId,
2565 encryption_settings: &EncryptionSettings,
2566 ) -> CollectRecipientsResult {
2567 let group_session = create_test_outbound_group_session(machine, encryption_settings);
2568 collect_session_recipients(
2569 machine.store(),
2570 iter::once(target_user_id),
2571 encryption_settings,
2572 &group_session,
2573 )
2574 .await
2575 .unwrap()
2576 }
2577
2578 fn assert_shared_with(
2581 recips: CollectRecipientsResult,
2582 user_id: &UserId,
2583 device_ids: HashSet<&DeviceId>,
2584 ) {
2585 let bob_devices_shared: HashSet<_> = recips
2586 .devices
2587 .get(user_id)
2588 .unwrap_or_else(|| panic!("session not shared with {user_id}"))
2589 .iter()
2590 .map(|d| d.device_id())
2591 .collect();
2592 assert_eq!(bob_devices_shared, device_ids);
2593
2594 assert!(recips.withheld_devices.is_empty(), "Unexpected withheld messages");
2595 }
2596
2597 fn assert_withheld_to(
2600 recips: CollectRecipientsResult,
2601 bob_user_id: &UserId,
2602 bob_dehydrated_device_id: &DeviceId,
2603 ) {
2604 for (user, device_list) in recips.devices {
2606 assert_eq!(device_list.len(), 0, "session unexpectedly shared with {user}");
2607 }
2608
2609 assert_eq!(recips.withheld_devices.len(), 1);
2611 assert_eq!(recips.withheld_devices[0].0.user_id(), bob_user_id);
2612 assert_eq!(recips.withheld_devices[0].0.device_id(), bob_dehydrated_device_id);
2613 assert_eq!(recips.withheld_devices[0].1, WithheldCode::Unverified);
2614 }
2615
2616 fn key_query_response_template_with_cross_signing(
2619 user_id: &UserId,
2620 ) -> KeyQueryResponseTemplate {
2621 KeyQueryResponseTemplate::new(user_id.to_owned()).with_cross_signing_keys(
2622 Ed25519SecretKey::from_slice(b"master12master12master12master12"),
2623 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2624 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2625 )
2626 }
2627
2628 fn key_query_response_template_with_changed_cross_signing(
2632 bob_user_id: &UserId,
2633 ) -> KeyQueryResponseTemplate {
2634 KeyQueryResponseTemplate::new(bob_user_id.to_owned()).with_cross_signing_keys(
2635 Ed25519SecretKey::from_slice(b"newmaster__newmaster__newmaster_"),
2636 Ed25519SecretKey::from_slice(b"self1234self1234self1234self1234"),
2637 Ed25519SecretKey::from_slice(b"user1234user1234user1234user1234"),
2638 )
2639 }
2640
2641 trait KeyQueryResponseTemplateExt {
2642 fn with_dehydrated_device(
2643 self,
2644 device_id: &DeviceId,
2645 verified: bool,
2646 ) -> KeyQueryResponseTemplate;
2647 }
2648
2649 impl KeyQueryResponseTemplateExt for KeyQueryResponseTemplate {
2650 fn with_dehydrated_device(
2652 self,
2653 device_id: &DeviceId,
2654 verified: bool,
2655 ) -> KeyQueryResponseTemplate {
2656 self.with_device(
2657 device_id,
2658 &Curve25519PublicKey::from(b"curvepubcurvepubcurvepubcurvepub".to_owned()),
2659 &Ed25519SecretKey::from_slice(b"device12device12device12device12"),
2660 KeyQueryResponseTemplateDeviceOptions::new()
2661 .dehydrated(true)
2662 .verified(verified),
2663 )
2664 }
2665 }
2666 }
2667
2668 #[async_test]
2669 async fn test_share_with_identity_strategy() {
2670 let machine = test_machine().await;
2671 import_known_users_to_test_machine(&machine).await;
2672
2673 let encryption_settings = identity_based_strategy_settings();
2674
2675 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2676
2677 let share_result = collect_session_recipients(
2678 machine.store(),
2679 vec![
2680 KeyDistributionTestData::dan_id(),
2681 KeyDistributionTestData::dave_id(),
2682 KeyDistributionTestData::good_id(),
2683 ]
2684 .into_iter(),
2685 &encryption_settings,
2686 &group_session,
2687 )
2688 .await
2689 .unwrap();
2690
2691 assert!(!share_result.should_rotate);
2692
2693 let dave_devices_shared = share_result.devices.get(KeyDistributionTestData::dave_id());
2694 let good_devices_shared = share_result.devices.get(KeyDistributionTestData::good_id());
2695 assert!(dave_devices_shared.unwrap().is_empty());
2697
2698 assert_eq!(good_devices_shared.unwrap().len(), 2);
2700
2701 let dan_devices_shared =
2704 share_result.devices.get(KeyDistributionTestData::dan_id()).unwrap();
2705
2706 assert_eq!(dan_devices_shared.len(), 1);
2707 let dan_device_that_will_get_the_key = &dan_devices_shared[0];
2708 assert_eq!(
2709 dan_device_that_will_get_the_key.device_id().as_str(),
2710 KeyDistributionTestData::dan_signed_device_id()
2711 );
2712
2713 let (_, code) = share_result
2715 .withheld_devices
2716 .iter()
2717 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dan_unsigned_device_id())
2718 .expect("This dan's device should receive a withheld code");
2719
2720 assert_eq!(code, &WithheldCode::Unverified);
2721
2722 let (_, code) = share_result
2724 .withheld_devices
2725 .iter()
2726 .find(|(d, _)| d.device_id() == KeyDistributionTestData::dave_device_id())
2727 .expect("This dave device should receive a withheld code");
2728
2729 assert_eq!(code, &WithheldCode::Unverified);
2730 }
2731
2732 #[async_test]
2735 async fn test_share_identity_strategy_no_cross_signing() {
2736 let machine: OlmMachine = OlmMachine::new(
2739 KeyDistributionTestData::me_id(),
2740 KeyDistributionTestData::me_device_id(),
2741 )
2742 .await;
2743
2744 let keys_query = KeyDistributionTestData::dan_keys_query_response();
2745 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2746
2747 let fake_room_id = room_id!("!roomid:localhost");
2748
2749 let encryption_settings = identity_based_strategy_settings();
2750
2751 let request_result = machine
2752 .share_room_key(
2753 fake_room_id,
2754 iter::once(KeyDistributionTestData::dan_id()),
2755 encryption_settings.clone(),
2756 )
2757 .await;
2758
2759 assert_matches!(
2760 request_result,
2761 Err(OlmError::SessionRecipientCollectionError(
2762 SessionRecipientCollectionError::CrossSigningNotSetup
2763 ))
2764 );
2765
2766 let keys_query = KeyDistributionTestData::me_keys_query_response();
2770 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2771
2772 let request_result = machine
2773 .share_room_key(
2774 fake_room_id,
2775 iter::once(KeyDistributionTestData::dan_id()),
2776 encryption_settings.clone(),
2777 )
2778 .await;
2779
2780 assert_matches!(
2781 request_result,
2782 Err(OlmError::SessionRecipientCollectionError(
2783 SessionRecipientCollectionError::SendingFromUnverifiedDevice
2784 ))
2785 );
2786
2787 machine
2790 .import_cross_signing_keys(CrossSigningKeyExport {
2791 master_key: KeyDistributionTestData::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
2792 self_signing_key: KeyDistributionTestData::SELF_SIGNING_KEY_PRIVATE_EXPORT
2793 .to_owned()
2794 .into(),
2795 user_signing_key: KeyDistributionTestData::USER_SIGNING_KEY_PRIVATE_EXPORT
2796 .to_owned()
2797 .into(),
2798 })
2799 .await
2800 .unwrap();
2801
2802 let requests = machine
2803 .share_room_key(
2804 fake_room_id,
2805 iter::once(KeyDistributionTestData::dan_id()),
2806 encryption_settings.clone(),
2807 )
2808 .await
2809 .unwrap();
2810
2811 assert_eq!(requests.len(), 1);
2814 }
2815
2816 #[async_test]
2820 async fn test_share_identity_strategy_report_verification_violation() {
2821 let machine: OlmMachine = OlmMachine::new(
2822 KeyDistributionTestData::me_id(),
2823 KeyDistributionTestData::me_device_id(),
2824 )
2825 .await;
2826
2827 machine.bootstrap_cross_signing(false).await.unwrap();
2828
2829 let user1 = IdentityChangeDataSet::user_id();
2831 let user2 = MaloIdentityChangeDataSet::user_id();
2832
2833 let keys_query = IdentityChangeDataSet::key_query_with_identity_a();
2835 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2836
2837 let keys_query = MaloIdentityChangeDataSet::initial_key_query();
2838 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2839
2840 let keys_query = IdentityChangeDataSet::key_query_with_identity_b();
2844 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2845 machine
2846 .get_identity(user1, None)
2847 .await
2848 .unwrap()
2849 .unwrap()
2850 .other()
2851 .unwrap()
2852 .mark_as_previously_verified()
2853 .await
2854 .unwrap();
2855
2856 let keys_query = MaloIdentityChangeDataSet::updated_key_query();
2857 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
2858 machine
2859 .get_identity(user2, None)
2860 .await
2861 .unwrap()
2862 .unwrap()
2863 .other()
2864 .unwrap()
2865 .mark_as_previously_verified()
2866 .await
2867 .unwrap();
2868
2869 let fake_room_id = room_id!("!roomid:localhost");
2870
2871 let encryption_settings = identity_based_strategy_settings();
2873
2874 let request_result = machine
2875 .share_room_key(
2876 fake_room_id,
2877 vec![user1, user2].into_iter(),
2878 encryption_settings.clone(),
2879 )
2880 .await;
2881
2882 assert_let!(
2885 Err(OlmError::SessionRecipientCollectionError(
2886 SessionRecipientCollectionError::VerifiedUserChangedIdentity(affected_users)
2887 )) = request_result
2888 );
2889 assert_eq!(2, affected_users.len());
2891
2892 machine
2894 .get_identity(user1, None)
2895 .await
2896 .unwrap()
2897 .unwrap()
2898 .withdraw_verification()
2899 .await
2900 .unwrap();
2901
2902 let verification_request = machine
2904 .get_identity(user2, None)
2905 .await
2906 .unwrap()
2907 .unwrap()
2908 .other()
2909 .unwrap()
2910 .verify()
2911 .await
2912 .unwrap();
2913
2914 let master_key =
2915 &machine.get_identity(user2, None).await.unwrap().unwrap().other().unwrap().master_key;
2916
2917 let my_identity = machine
2918 .get_identity(KeyDistributionTestData::me_id(), None)
2919 .await
2920 .expect("Should not fail to find own identity")
2921 .expect("Our own identity should not be missing")
2922 .own()
2923 .expect("Our own identity should be of type Own");
2924
2925 let msk = json!({ user2: serde_json::to_value(master_key).expect("Should not fail to serialize")});
2926 let ssk =
2927 serde_json::to_value(&MaloIdentityChangeDataSet::updated_key_query().self_signing_keys)
2928 .expect("Should not fail to serialize");
2929
2930 let kq_response = simulate_key_query_response_for_verification(
2931 verification_request,
2932 my_identity,
2933 KeyDistributionTestData::me_id(),
2934 user2,
2935 msk,
2936 ssk,
2937 );
2938
2939 machine
2940 .mark_request_as_sent(
2941 &TransactionId::new(),
2942 crate::types::requests::AnyIncomingResponse::KeysQuery(&kq_response),
2943 )
2944 .await
2945 .unwrap();
2946
2947 assert!(machine.get_identity(user2, None).await.unwrap().unwrap().is_verified());
2948
2949 machine
2951 .share_room_key(
2952 fake_room_id,
2953 vec![user1, user2].into_iter(),
2954 encryption_settings.clone(),
2955 )
2956 .await
2957 .unwrap();
2958 }
2959
2960 #[async_test]
2961 async fn test_should_rotate_based_on_visibility() {
2962 let machine = test_machine().await;
2963 import_known_users_to_test_machine(&machine).await;
2964
2965 let strategy = CollectStrategy::AllDevices;
2966
2967 let encryption_settings = EncryptionSettings {
2968 sharing_strategy: strategy.clone(),
2969 history_visibility: HistoryVisibility::Invited,
2970 ..Default::default()
2971 };
2972
2973 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
2974
2975 let _ = collect_session_recipients(
2976 machine.store(),
2977 vec![KeyDistributionTestData::dan_id()].into_iter(),
2978 &encryption_settings,
2979 &group_session,
2980 )
2981 .await
2982 .unwrap();
2983
2984 let encryption_settings = EncryptionSettings {
2986 sharing_strategy: strategy.clone(),
2987 history_visibility: HistoryVisibility::Shared,
2988 ..Default::default()
2989 };
2990
2991 let share_result = collect_session_recipients(
2992 machine.store(),
2993 vec![KeyDistributionTestData::dan_id()].into_iter(),
2994 &encryption_settings,
2995 &group_session,
2996 )
2997 .await
2998 .unwrap();
2999
3000 assert!(share_result.should_rotate);
3001 }
3002
3003 #[async_test]
3007 async fn test_should_rotate_based_on_device_excluded() {
3008 let machine = test_machine().await;
3009 import_known_users_to_test_machine(&machine).await;
3010
3011 let encryption_settings = all_devices_strategy_settings();
3012 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3013 let sender_key = machine.identity_keys().curve25519;
3014
3015 group_session
3016 .mark_shared_with(
3017 KeyDistributionTestData::dan_id(),
3018 KeyDistributionTestData::dan_signed_device_id(),
3019 sender_key,
3020 )
3021 .await;
3022 group_session
3023 .mark_shared_with(
3024 KeyDistributionTestData::dan_id(),
3025 KeyDistributionTestData::dan_unsigned_device_id(),
3026 sender_key,
3027 )
3028 .await;
3029
3030 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3032 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3033
3034 let share_result = collect_session_recipients(
3036 machine.store(),
3037 vec![KeyDistributionTestData::dan_id()].into_iter(),
3038 &encryption_settings,
3039 &group_session,
3040 )
3041 .await
3042 .unwrap();
3043
3044 assert!(share_result.should_rotate);
3045 }
3046
3047 #[async_test]
3050 async fn test_should_rotate_based_on_device_with_pending_request_excluded() {
3051 let machine = test_machine().await;
3052 import_known_users_to_test_machine(&machine).await;
3053
3054 let encryption_settings = all_devices_strategy_settings();
3055 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3056 let sender_key = machine.identity_keys().curve25519;
3057
3058 let dan_user = KeyDistributionTestData::dan_id();
3059 let dan_dev1 = KeyDistributionTestData::dan_signed_device_id();
3060 let dan_dev2 = KeyDistributionTestData::dan_unsigned_device_id();
3061
3062 group_session.mark_shared_with(dan_user, dan_dev1, sender_key).await;
3064
3065 {
3066 let share_infos = BTreeMap::from([(
3068 dan_user.to_owned(),
3069 BTreeMap::from([(
3070 dan_dev2.to_owned(),
3071 ShareInfo::new_shared(sender_key, 0, SequenceNumber::default()),
3072 )]),
3073 )]);
3074
3075 let txid = TransactionId::new();
3076 let req = Arc::new(ToDeviceRequest::for_recipients(
3077 dan_user,
3078 vec![dan_dev2.to_owned()],
3079 &ruma::events::AnyToDeviceEventContent::Dummy(ToDeviceDummyEventContent),
3080 txid.clone(),
3081 ));
3082 group_session.add_request(txid, req, share_infos);
3083 }
3084
3085 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3087 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3088
3089 let share_result = collect_session_recipients(
3091 machine.store(),
3092 vec![KeyDistributionTestData::dan_id()].into_iter(),
3093 &encryption_settings,
3094 &group_session,
3095 )
3096 .await
3097 .unwrap();
3098
3099 assert!(share_result.should_rotate);
3100 }
3101
3102 #[async_test]
3105 async fn test_should_not_rotate_if_keys_were_withheld() {
3106 let machine = test_machine().await;
3107 import_known_users_to_test_machine(&machine).await;
3108
3109 let encryption_settings = all_devices_strategy_settings();
3110 let group_session = create_test_outbound_group_session(&machine, &encryption_settings);
3111 let fake_room_id = group_session.room_id();
3112
3113 let requests = machine
3116 .share_room_key(
3117 fake_room_id,
3118 vec![KeyDistributionTestData::dan_id()].into_iter(),
3119 encryption_settings.clone(),
3120 )
3121 .await
3122 .unwrap();
3123
3124 for r in requests {
3125 machine
3126 .inner
3127 .group_session_manager
3128 .mark_request_as_sent(r.as_ref().txn_id.as_ref())
3129 .await
3130 .unwrap();
3131 }
3132
3133 let keys_query = KeyDistributionTestData::dan_keys_query_response_device_loggedout();
3135 machine.mark_request_as_sent(&TransactionId::new(), &keys_query).await.unwrap();
3136
3137 let share_result = collect_session_recipients(
3139 machine.store(),
3140 vec![KeyDistributionTestData::dan_id()].into_iter(),
3141 &encryption_settings,
3142 &group_session,
3143 )
3144 .await
3145 .unwrap();
3146
3147 assert!(!share_result.should_rotate);
3148 }
3149
3150 async fn unsigned_of_verified_setup() -> OlmMachine {
3158 use test_json::keys_query_sets::VerificationViolationTestData as DataSet;
3159
3160 let machine = OlmMachine::new(DataSet::own_id(), device_id!("LOCAL")).await;
3161
3162 let own_keys = DataSet::own_keys_query_response_1();
3164 machine.mark_request_as_sent(&TransactionId::new(), &own_keys).await.unwrap();
3165
3166 machine
3168 .import_cross_signing_keys(CrossSigningKeyExport {
3169 master_key: DataSet::MASTER_KEY_PRIVATE_EXPORT.to_owned().into(),
3170 self_signing_key: DataSet::SELF_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3171 user_signing_key: DataSet::USER_SIGNING_KEY_PRIVATE_EXPORT.to_owned().into(),
3172 })
3173 .await
3174 .unwrap();
3175
3176 let bob_keys = DataSet::bob_keys_query_response_signed();
3178 machine.mark_request_as_sent(&TransactionId::new(), &bob_keys).await.unwrap();
3179
3180 let bob_identity = machine.get_identity(DataSet::bob_id(), None).await.unwrap().unwrap();
3183 assert!(bob_identity.other().unwrap().is_verified());
3184
3185 let bob_signed_device = machine
3186 .get_device(DataSet::bob_id(), DataSet::bob_device_1_id(), None)
3187 .await
3188 .unwrap()
3189 .unwrap();
3190 assert!(bob_signed_device.is_verified());
3191 assert!(bob_signed_device.device_owner_identity.is_some());
3192
3193 let bob_unsigned_device = machine
3194 .get_device(DataSet::bob_id(), DataSet::bob_device_2_id(), None)
3195 .await
3196 .unwrap()
3197 .unwrap();
3198 assert!(!bob_unsigned_device.is_verified());
3199
3200 machine
3201 }
3202
3203 fn all_devices_strategy_settings() -> EncryptionSettings {
3205 EncryptionSettings { sharing_strategy: CollectStrategy::AllDevices, ..Default::default() }
3206 }
3207
3208 fn error_on_verification_problem_encryption_settings() -> EncryptionSettings {
3211 EncryptionSettings {
3212 sharing_strategy: CollectStrategy::ErrorOnVerifiedUserProblem,
3213 ..Default::default()
3214 }
3215 }
3216
3217 fn identity_based_strategy_settings() -> EncryptionSettings {
3219 EncryptionSettings {
3220 sharing_strategy: CollectStrategy::IdentityBasedStrategy,
3221 ..Default::default()
3222 }
3223 }
3224
3225 fn create_test_outbound_group_session(
3228 machine: &OlmMachine,
3229 encryption_settings: &EncryptionSettings,
3230 ) -> OutboundGroupSession {
3231 OutboundGroupSession::new(
3232 machine.device_id().into(),
3233 Arc::new(machine.identity_keys()),
3234 room_id!("!roomid:localhost"),
3235 encryption_settings.clone(),
3236 )
3237 .expect("creating an outbound group session should not fail")
3238 }
3239}