use ruma::events::room::encryption::RoomEncryptionEventContent;
use super::Room;
impl Room {
pub fn encryption_state(&self) -> EncryptionState {
self.info.read().encryption_state()
}
pub fn encryption_settings(&self) -> Option<RoomEncryptionEventContent> {
self.info.read().base_info.encryption.clone()
}
}
#[derive(Debug)]
#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
pub enum EncryptionState {
Encrypted,
#[cfg(feature = "experimental-encrypted-state-events")]
StateEncrypted,
NotEncrypted,
Unknown,
}
impl EncryptionState {
#[cfg(not(feature = "experimental-encrypted-state-events"))]
pub fn is_encrypted(&self) -> bool {
matches!(self, Self::Encrypted)
}
#[cfg(feature = "experimental-encrypted-state-events")]
pub fn is_encrypted(&self) -> bool {
matches!(self, Self::Encrypted | Self::StateEncrypted)
}
#[cfg(feature = "experimental-encrypted-state-events")]
pub fn is_state_encrypted(&self) -> bool {
matches!(self, Self::StateEncrypted)
}
pub fn is_unknown(&self) -> bool {
matches!(self, Self::Unknown)
}
}
#[cfg(test)]
mod tests {
use std::{
ops::{Not, Sub},
sync::Arc,
time::Duration,
};
use assert_matches::assert_matches;
use matrix_sdk_test::{ALICE, event_factory::EventFactory};
use ruma::{
EventEncryptionAlgorithm, MilliSecondsSinceUnixEpoch, event_id,
events::{AnySyncStateEvent, room::encryption::RoomEncryptionEventContent},
room_id,
time::SystemTime,
user_id,
};
use super::{EncryptionState, Room};
use crate::{RoomState, store::MemoryStore};
fn make_room_test_helper(room_type: RoomState) -> (Arc<MemoryStore>, Room) {
let store = Arc::new(MemoryStore::new());
let user_id = user_id!("@me:example.org");
let room_id = room_id!("!test:localhost");
let (sender, _receiver) = tokio::sync::broadcast::channel(1);
(store.clone(), Room::new(user_id, store, room_id, room_type, sender))
}
fn timestamp(minutes_ago: u32) -> MilliSecondsSinceUnixEpoch {
MilliSecondsSinceUnixEpoch::from_system_time(
SystemTime::now().sub(Duration::from_secs((60 * minutes_ago).into())),
)
.expect("date out of range")
}
fn receive_state_events(room: &Room, events: Vec<&AnySyncStateEvent>) {
room.info.update_if(|info| {
let mut res = false;
for ev in events {
res |= info.handle_state_event(ev);
}
res
});
}
#[test]
fn test_encryption_is_set_when_encryption_event_is_received_encrypted() {
let (_store, room) = make_room_test_helper(RoomState::Joined);
assert_matches!(room.encryption_state(), EncryptionState::Unknown);
let encryption_content =
RoomEncryptionEventContent::new(EventEncryptionAlgorithm::MegolmV1AesSha2);
let encryption_event = EventFactory::new()
.sender(*ALICE)
.event(encryption_content)
.state_key("")
.event_id(event_id!("$1234_1"))
.server_ts(timestamp(0))
.into();
receive_state_events(&room, vec![&encryption_event]);
assert_matches!(room.encryption_state(), EncryptionState::Encrypted);
}
#[test]
fn test_encryption_is_set_when_encryption_event_is_received_not_encrypted() {
let (_store, room) = make_room_test_helper(RoomState::Joined);
assert_matches!(room.encryption_state(), EncryptionState::Unknown);
room.info.update_if(|info| {
info.mark_encryption_state_synced();
false
});
assert_matches!(room.encryption_state(), EncryptionState::NotEncrypted);
}
#[test]
fn test_encryption_state() {
assert!(EncryptionState::Unknown.is_unknown());
assert!(EncryptionState::Encrypted.is_unknown().not());
assert!(EncryptionState::NotEncrypted.is_unknown().not());
assert!(EncryptionState::Unknown.is_encrypted().not());
assert!(EncryptionState::Encrypted.is_encrypted());
assert!(EncryptionState::NotEncrypted.is_encrypted().not());
#[cfg(feature = "experimental-encrypted-state-events")]
{
assert!(EncryptionState::StateEncrypted.is_unknown().not());
assert!(EncryptionState::StateEncrypted.is_encrypted());
assert!(EncryptionState::Unknown.is_state_encrypted().not());
assert!(EncryptionState::Encrypted.is_state_encrypted().not());
assert!(EncryptionState::StateEncrypted.is_state_encrypted());
assert!(EncryptionState::NotEncrypted.is_state_encrypted().not());
}
}
}