use matrix_sdk_common::{
events::forwarded_room_key::ForwardedRoomKeyToDeviceEventContent,
identifiers::{DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId},
};
use serde::{Deserialize, Serialize};
use std::{collections::BTreeMap, convert::TryInto};
use zeroize::Zeroize;
mod inbound;
mod outbound;
pub use inbound::{InboundGroupSession, InboundGroupSessionPickle, PickledInboundGroupSession};
pub use outbound::{EncryptionSettings, OutboundGroupSession};
#[derive(Clone, Debug, Serialize, Deserialize, Zeroize)]
#[zeroize(drop)]
pub struct GroupSessionKey(pub String);
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Zeroize)]
#[zeroize(drop)]
pub struct ExportedGroupSessionKey(pub String);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct ExportedRoomKey {
pub algorithm: EventEncryptionAlgorithm,
pub room_id: RoomId,
pub sender_key: String,
pub session_id: String,
pub session_key: ExportedGroupSessionKey,
pub sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String>,
pub forwarding_curve25519_key_chain: Vec<String>,
}
impl TryInto<ForwardedRoomKeyToDeviceEventContent> for ExportedRoomKey {
type Error = ();
fn try_into(self) -> Result<ForwardedRoomKeyToDeviceEventContent, Self::Error> {
if self.sender_claimed_keys.len() != 1 {
Err(())
} else {
let (algorithm, claimed_key) = self.sender_claimed_keys.iter().next().ok_or(())?;
if algorithm != &DeviceKeyAlgorithm::Ed25519 {
return Err(());
}
Ok(ForwardedRoomKeyToDeviceEventContent {
algorithm: self.algorithm,
room_id: self.room_id,
sender_key: self.sender_key,
session_id: self.session_id,
session_key: self.session_key.0.clone(),
sender_claimed_ed25519_key: claimed_key.to_owned(),
forwarding_curve25519_key_chain: self.forwarding_curve25519_key_chain,
})
}
}
}
impl From<ForwardedRoomKeyToDeviceEventContent> for ExportedRoomKey {
fn from(forwarded_key: ForwardedRoomKeyToDeviceEventContent) -> Self {
let mut sender_claimed_keys: BTreeMap<DeviceKeyAlgorithm, String> = BTreeMap::new();
sender_claimed_keys.insert(
DeviceKeyAlgorithm::Ed25519,
forwarded_key.sender_claimed_ed25519_key,
);
Self {
algorithm: forwarded_key.algorithm,
room_id: forwarded_key.room_id,
session_id: forwarded_key.session_id,
forwarding_curve25519_key_chain: forwarded_key.forwarding_curve25519_key_chain,
sender_claimed_keys,
sender_key: forwarded_key.sender_key,
session_key: ExportedGroupSessionKey(forwarded_key.session_key),
}
}
}
#[cfg(test)]
mod test {
use std::{
sync::Arc,
time::{Duration, Instant},
};
use matrix_sdk_common::{
events::{
room::message::{MessageEventContent, TextMessageEventContent},
AnyMessageEventContent,
},
identifiers::{room_id, user_id},
};
use super::EncryptionSettings;
use crate::ReadOnlyAccount;
#[tokio::test]
#[cfg(target_os = "linux")]
async fn expiration() {
let settings = EncryptionSettings {
rotation_period_msgs: 1,
..Default::default()
};
let account = ReadOnlyAccount::new(&user_id!("@alice:example.org"), "DEVICEID".into());
let (session, _) = account
.create_group_session_pair(&room_id!("!test_room:example.org"), settings)
.await
.unwrap();
assert!(!session.expired());
let _ = session
.encrypt(AnyMessageEventContent::RoomMessage(
MessageEventContent::Text(TextMessageEventContent::plain("Test message")),
))
.await;
assert!(session.expired());
let settings = EncryptionSettings {
rotation_period: Duration::from_millis(100),
..Default::default()
};
let (mut session, _) = account
.create_group_session_pair(&room_id!("!test_room:example.org"), settings)
.await
.unwrap();
assert!(!session.expired());
session.creation_time = Arc::new(Instant::now() - Duration::from_secs(60 * 60));
assert!(session.expired());
}
}