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 #[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 str::FromStr,
84 sync::Arc,
85 time::Duration,
86 };
87
88 use assert_matches::assert_matches;
89 use matrix_sdk_test::ALICE;
90 use ruma::{
91 EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, OwnedEventId,
92 events::{
93 AnySyncStateEvent, EmptyStateKey, StateUnsigned, SyncStateEvent,
94 room::encryption::{OriginalSyncRoomEncryptionEvent, RoomEncryptionEventContent},
95 },
96 room_id,
97 time::SystemTime,
98 user_id,
99 };
100
101 use super::{EncryptionState, Room};
102 use crate::{RoomState, store::MemoryStore};
103
104 fn make_room_test_helper(room_type: RoomState) -> (Arc<MemoryStore>, Room) {
105 let store = Arc::new(MemoryStore::new());
106 let user_id = user_id!("@me:example.org");
107 let room_id = room_id!("!test:localhost");
108 let (sender, _receiver) = tokio::sync::broadcast::channel(1);
109
110 (store.clone(), Room::new(user_id, store, room_id, room_type, sender))
111 }
112
113 fn timestamp(minutes_ago: u32) -> MilliSecondsSinceUnixEpoch {
114 MilliSecondsSinceUnixEpoch::from_system_time(
115 SystemTime::now().sub(Duration::from_secs((60 * minutes_ago).into())),
116 )
117 .expect("date out of range")
118 }
119
120 fn receive_state_events(room: &Room, events: Vec<&AnySyncStateEvent>) {
121 room.inner.update_if(|info| {
122 let mut res = false;
123 for ev in events {
124 res |= info.handle_state_event(ev);
125 }
126 res
127 });
128 }
129
130 #[test]
131 fn test_encryption_is_set_when_encryption_event_is_received_encrypted() {
132 let (_store, room) = make_room_test_helper(RoomState::Joined);
133
134 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
135
136 let encryption_content =
137 RoomEncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
138 let encryption_event = AnySyncStateEvent::RoomEncryption(SyncStateEvent::Original(
139 OriginalSyncRoomEncryptionEvent {
140 content: encryption_content,
141 event_id: OwnedEventId::from_str("$1234_1").unwrap(),
142 sender: ALICE.to_owned(),
143 origin_server_ts: timestamp(0),
146 state_key: EmptyStateKey,
147 unsigned: StateUnsigned::new(),
148 },
149 ));
150 receive_state_events(&room, vec![&encryption_event]);
151
152 assert_matches!(room.encryption_state(), EncryptionState::Encrypted);
153 }
154
155 #[test]
156 fn test_encryption_is_set_when_encryption_event_is_received_not_encrypted() {
157 let (_store, room) = make_room_test_helper(RoomState::Joined);
158
159 assert_matches!(room.encryption_state(), EncryptionState::Unknown);
160 room.inner.update_if(|info| {
161 info.mark_encryption_state_synced();
162
163 false
164 });
165
166 assert_matches!(room.encryption_state(), EncryptionState::NotEncrypted);
167 }
168
169 #[test]
170 fn test_encryption_state() {
171 assert!(EncryptionState::Unknown.is_unknown());
172 assert!(EncryptionState::Encrypted.is_unknown().not());
173 assert!(EncryptionState::NotEncrypted.is_unknown().not());
174
175 assert!(EncryptionState::Unknown.is_encrypted().not());
176 assert!(EncryptionState::Encrypted.is_encrypted());
177 assert!(EncryptionState::NotEncrypted.is_encrypted().not());
178
179 #[cfg(feature = "experimental-encrypted-state-events")]
180 {
181 assert!(EncryptionState::StateEncrypted.is_unknown().not());
182 assert!(EncryptionState::StateEncrypted.is_encrypted());
183
184 assert!(EncryptionState::Unknown.is_state_encrypted().not());
185 assert!(EncryptionState::Encrypted.is_state_encrypted().not());
186 assert!(EncryptionState::StateEncrypted.is_state_encrypted());
187 assert!(EncryptionState::NotEncrypted.is_state_encrypted().not());
188 }
189 }
190}