matrix_sdk_base/room/
encryption.rs1use ruma::events::room::encryption::RoomEncryptionEventContent;
16
17use super::Room;
18
19impl Room {
20 pub fn encryption_state(&self) -> EncryptionState {
22 self.inner.read().encryption_state()
23 }
24
25 pub fn encryption_settings(&self) -> Option<RoomEncryptionEventContent> {
28 self.inner.read().base_info.encryption.clone()
29 }
30}
31
32#[derive(Debug)]
34#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
35pub enum EncryptionState {
36 Encrypted,
38
39 NotEncrypted,
41
42 Unknown,
45}
46
47impl EncryptionState {
48 pub fn is_encrypted(&self) -> bool {
50 matches!(self, Self::Encrypted)
51 }
52
53 pub fn is_unknown(&self) -> bool {
55 matches!(self, Self::Unknown)
56 }
57}
58
59#[cfg(test)]
60mod tests {
61 use std::{
62 ops::{Not, Sub},
63 str::FromStr,
64 sync::Arc,
65 time::Duration,
66 };
67
68 use assert_matches::assert_matches;
69 use matrix_sdk_test::ALICE;
70 use ruma::{
71 EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, OwnedEventId,
72 events::{
73 AnySyncStateEvent, EmptyStateKey, StateUnsigned, SyncStateEvent,
74 room::encryption::{OriginalSyncRoomEncryptionEvent, RoomEncryptionEventContent},
75 },
76 room_id,
77 time::SystemTime,
78 user_id,
79 };
80
81 use super::{EncryptionState, Room};
82 use crate::{RoomState, store::MemoryStore};
83
84 fn make_room_test_helper(room_type: RoomState) -> (Arc<MemoryStore>, Room) {
85 let store = Arc::new(MemoryStore::new());
86 let user_id = user_id!("@me:example.org");
87 let room_id = room_id!("!test:localhost");
88 let (sender, _receiver) = tokio::sync::broadcast::channel(1);
89
90 (store.clone(), Room::new(user_id, store, room_id, room_type, sender))
91 }
92
93 fn timestamp(minutes_ago: u32) -> MilliSecondsSinceUnixEpoch {
94 MilliSecondsSinceUnixEpoch::from_system_time(
95 SystemTime::now().sub(Duration::from_secs((60 * minutes_ago).into())),
96 )
97 .expect("date out of range")
98 }
99
100 fn receive_state_events(room: &Room, events: Vec<&AnySyncStateEvent>) {
101 room.inner.update_if(|info| {
102 let mut res = false;
103 for ev in events {
104 res |= info.handle_state_event(ev);
105 }
106 res
107 });
108 }
109
110 #[test]
111 fn test_encryption_is_set_when_encryption_event_is_received_encrypted() {
112 let (_store, room) = make_room_test_helper(RoomState::Joined);
113
114 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
115
116 let encryption_content =
117 RoomEncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
118 let encryption_event = AnySyncStateEvent::RoomEncryption(SyncStateEvent::Original(
119 OriginalSyncRoomEncryptionEvent {
120 content: encryption_content,
121 event_id: OwnedEventId::from_str("$1234_1").unwrap(),
122 sender: ALICE.to_owned(),
123 origin_server_ts: timestamp(0),
126 state_key: EmptyStateKey,
127 unsigned: StateUnsigned::new(),
128 },
129 ));
130 receive_state_events(&room, vec![&encryption_event]);
131
132 assert_matches!(room.encryption_state(), EncryptionState::Encrypted);
133 }
134
135 #[test]
136 fn test_encryption_is_set_when_encryption_event_is_received_not_encrypted() {
137 let (_store, room) = make_room_test_helper(RoomState::Joined);
138
139 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
140 room.inner.update_if(|info| {
141 info.mark_encryption_state_synced();
142
143 false
144 });
145
146 assert_matches!(room.encryption_state(), EncryptionState::NotEncrypted);
147 }
148
149 #[test]
150 fn test_encryption_state() {
151 assert!(EncryptionState::Unknown.is_unknown());
152 assert!(EncryptionState::Encrypted.is_unknown().not());
153 assert!(EncryptionState::NotEncrypted.is_unknown().not());
154
155 assert!(EncryptionState::Unknown.is_encrypted().not());
156 assert!(EncryptionState::Encrypted.is_encrypted());
157 assert!(EncryptionState::NotEncrypted.is_encrypted().not());
158 }
159}