matrix_sdk_base/room/
encryption.rs1use ruma::events::room::encryption::PossiblyRedactedRoomEncryptionEventContent;
16
17use super::Room;
18
19impl Room {
20 pub fn encryption_state(&self) -> EncryptionState {
22 self.info.read().encryption_state()
23 }
24
25 pub fn encryption_settings(&self) -> Option<PossiblyRedactedRoomEncryptionEventContent> {
28 self.info.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 #[cfg(feature = "experimental-encrypted-state-events")]
42 StateEncrypted,
43
44 NotEncrypted,
46
47 Unknown,
50}
51
52impl EncryptionState {
53 #[cfg(not(feature = "experimental-encrypted-state-events"))]
55 pub fn is_encrypted(&self) -> bool {
56 matches!(self, Self::Encrypted)
57 }
58
59 #[cfg(feature = "experimental-encrypted-state-events")]
62 pub fn is_encrypted(&self) -> bool {
63 matches!(self, Self::Encrypted | Self::StateEncrypted)
64 }
65
66 #[cfg(feature = "experimental-encrypted-state-events")]
69 pub fn is_state_encrypted(&self) -> bool {
70 matches!(self, Self::StateEncrypted)
71 }
72
73 pub fn is_unknown(&self) -> bool {
75 matches!(self, Self::Unknown)
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use std::{
82 ops::{Not, Sub},
83 sync::Arc,
84 time::Duration,
85 };
86
87 use assert_matches::assert_matches;
88 use matrix_sdk_test::{ALICE, event_factory::EventFactory};
89 use ruma::{
90 EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, event_id,
91 events::{AnySyncStateEvent, room::encryption::RoomEncryptionEventContent},
92 room_id,
93 serde::Raw,
94 time::SystemTime,
95 user_id,
96 };
97
98 use super::{EncryptionState, Room};
99 use crate::{
100 RoomState,
101 store::{MemoryStore, SaveLockedStateStore},
102 utils::RawStateEventWithKeys,
103 };
104
105 fn make_room_test_helper(room_type: RoomState) -> (Arc<MemoryStore>, Room) {
106 let store = Arc::new(MemoryStore::new());
107 let user_id = user_id!("@me:example.org");
108 let room_id = room_id!("!test:localhost");
109 let (sender, _receiver) = tokio::sync::broadcast::channel(1);
110
111 (
112 store.clone(),
113 Room::new(user_id, SaveLockedStateStore::new(store), room_id, room_type, sender),
114 )
115 }
116
117 fn timestamp(minutes_ago: u32) -> MilliSecondsSinceUnixEpoch {
118 MilliSecondsSinceUnixEpoch::from_system_time(
119 SystemTime::now().sub(Duration::from_secs((60 * minutes_ago).into())),
120 )
121 .expect("date out of range")
122 }
123
124 fn receive_state_events(room: &Room, events: Vec<Raw<AnySyncStateEvent>>) {
125 room.info.update_if(|info| {
126 let mut res = false;
127 for ev in events {
128 res |= info.handle_state_event(
129 &mut RawStateEventWithKeys::try_from_raw_state_event(ev)
130 .expect("generated state event should be valid"),
131 );
132 }
133 res
134 });
135 }
136
137 #[test]
138 fn test_encryption_is_set_when_encryption_event_is_received_encrypted() {
139 let (_store, room) = make_room_test_helper(RoomState::Joined);
140
141 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
142
143 let encryption_content =
144 RoomEncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
145 let encryption_event = EventFactory::new()
146 .sender(*ALICE)
147 .event(encryption_content)
148 .state_key("")
149 .event_id(event_id!("$1234_1"))
150 .server_ts(timestamp(0))
153 .into();
154 receive_state_events(&room, vec![encryption_event]);
155
156 assert_matches!(room.encryption_state(), EncryptionState::Encrypted);
157 }
158
159 #[test]
160 fn test_encryption_is_set_when_encryption_event_is_received_not_encrypted() {
161 let (_store, room) = make_room_test_helper(RoomState::Joined);
162
163 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
164 room.info.update_if(|info| {
165 info.mark_encryption_state_synced();
166
167 false
168 });
169
170 assert_matches!(room.encryption_state(), EncryptionState::NotEncrypted);
171 }
172
173 #[test]
174 fn test_encryption_state() {
175 assert!(EncryptionState::Unknown.is_unknown());
176 assert!(EncryptionState::Encrypted.is_unknown().not());
177 assert!(EncryptionState::NotEncrypted.is_unknown().not());
178
179 assert!(EncryptionState::Unknown.is_encrypted().not());
180 assert!(EncryptionState::Encrypted.is_encrypted());
181 assert!(EncryptionState::NotEncrypted.is_encrypted().not());
182
183 #[cfg(feature = "experimental-encrypted-state-events")]
184 {
185 assert!(EncryptionState::StateEncrypted.is_unknown().not());
186 assert!(EncryptionState::StateEncrypted.is_encrypted());
187
188 assert!(EncryptionState::Unknown.is_state_encrypted().not());
189 assert!(EncryptionState::Encrypted.is_state_encrypted().not());
190 assert!(EncryptionState::StateEncrypted.is_state_encrypted());
191 assert!(EncryptionState::NotEncrypted.is_state_encrypted().not());
192 }
193 }
194}