Merge branch 'poljar/session-timestamp-improvements'
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use instant::SystemTime;
|
||||
use ruma::MilliSecondsSinceUnixEpoch;
|
||||
use ruma::{MilliSecondsSinceUnixEpoch, SecondsSinceUnixEpoch};
|
||||
|
||||
/// Platform agnostic helper function to create MilliSecondsSinceUnixEpoch
|
||||
pub fn milli_seconds_since_unix_epoch() -> MilliSecondsSinceUnixEpoch {
|
||||
@@ -9,3 +9,11 @@ pub fn milli_seconds_since_unix_epoch() -> MilliSecondsSinceUnixEpoch {
|
||||
duration.as_millis().try_into().expect("can't convert milliseconds since UNIXEPOCH");
|
||||
MilliSecondsSinceUnixEpoch(millis)
|
||||
}
|
||||
|
||||
/// Platform agnostic helper function to create SecondsSinceUnixEpoch
|
||||
pub fn seconds_since_unix_epoch() -> SecondsSinceUnixEpoch {
|
||||
let duration =
|
||||
SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).expect("now is always higher");
|
||||
let millis = duration.as_secs().try_into().expect("can't convert seconds since UNIXEPOCH");
|
||||
SecondsSinceUnixEpoch(millis)
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ impl RecoveryKey {
|
||||
let decoded = Zeroizing::new(crate::utilities::decode(key)?);
|
||||
|
||||
if decoded.len() != Self::KEY_SIZE {
|
||||
Err(DecodeError::Length(decoded.len(), Self::KEY_SIZE))
|
||||
Err(DecodeError::Length(Self::KEY_SIZE, decoded.len()))
|
||||
} else {
|
||||
let mut key = Box::new([0u8; Self::KEY_SIZE]);
|
||||
key.copy_from_slice(&decoded);
|
||||
|
||||
@@ -525,7 +525,8 @@ impl ReadOnlyDevice {
|
||||
};
|
||||
|
||||
let session = if let Some(s) = store.get_sessions(&sender_key.to_base64()).await? {
|
||||
let sessions = s.lock().await;
|
||||
let mut sessions = s.lock().await;
|
||||
sessions.sort_by_key(|s| s.last_use_time);
|
||||
sessions.get(0).cloned()
|
||||
} else {
|
||||
None
|
||||
|
||||
@@ -23,7 +23,7 @@ use std::{
|
||||
},
|
||||
};
|
||||
|
||||
use matrix_sdk_common::{instant::Instant, locks::Mutex};
|
||||
use matrix_sdk_common::{locks::Mutex, util::seconds_since_unix_epoch};
|
||||
use ruma::{
|
||||
api::client::keys::{
|
||||
upload_keys,
|
||||
@@ -921,7 +921,7 @@ impl ReadOnlyAccount {
|
||||
) -> Session {
|
||||
let session = self.inner.lock().await.create_outbound_session(identity_key, one_time_key);
|
||||
|
||||
let now = Instant::now();
|
||||
let now = seconds_since_unix_epoch();
|
||||
let session_id = session.session_id();
|
||||
|
||||
Session {
|
||||
@@ -932,8 +932,8 @@ impl ReadOnlyAccount {
|
||||
session_id: session_id.into(),
|
||||
sender_key: identity_key,
|
||||
created_using_fallback_key: fallback_used,
|
||||
creation_time: Arc::new(now),
|
||||
last_use_time: Arc::new(now),
|
||||
creation_time: now,
|
||||
last_use_time: now,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1017,7 +1017,7 @@ impl ReadOnlyAccount {
|
||||
let result =
|
||||
self.inner.lock().await.create_inbound_session(&their_identity_key, message)?;
|
||||
|
||||
let now = Instant::now();
|
||||
let now = seconds_since_unix_epoch();
|
||||
let session_id = result.session.session_id();
|
||||
|
||||
let session = Session {
|
||||
@@ -1028,8 +1028,8 @@ impl ReadOnlyAccount {
|
||||
session_id: session_id.into(),
|
||||
sender_key: their_identity_key,
|
||||
created_using_fallback_key: false,
|
||||
creation_time: Arc::new(now),
|
||||
last_use_time: Arc::new(now),
|
||||
creation_time: now,
|
||||
last_use_time: now,
|
||||
};
|
||||
|
||||
Ok(InboundCreationResult { session, plaintext: result.plaintext })
|
||||
|
||||
@@ -161,11 +161,14 @@ impl TryFrom<ToDeviceForwardedRoomKeyEventContent> for ExportedRoomKey {
|
||||
|
||||
#[cfg(all(test, any(target_os = "linux", target_arch = "wasm32")))]
|
||||
mod tests {
|
||||
use std::{sync::Arc, time::Duration};
|
||||
use std::time::Duration;
|
||||
|
||||
use matrix_sdk_common::instant::Instant;
|
||||
use matrix_sdk_common::instant::SystemTime;
|
||||
use matrix_sdk_test::async_test;
|
||||
use ruma::{device_id, events::room::message::RoomMessageEventContent, room_id, user_id};
|
||||
use ruma::{
|
||||
device_id, events::room::message::RoomMessageEventContent, room_id, user_id,
|
||||
SecondsSinceUnixEpoch,
|
||||
};
|
||||
|
||||
use super::EncryptionSettings;
|
||||
use crate::{MegolmError, ReadOnlyAccount};
|
||||
@@ -201,7 +204,8 @@ mod tests {
|
||||
|
||||
assert!(!session.expired());
|
||||
// FIXME: this might break on macosx and windows
|
||||
session.creation_time = Arc::new(Instant::now() - Duration::from_secs(60 * 60));
|
||||
let time = SystemTime::now() - Duration::from_secs(60 * 60);
|
||||
session.creation_time = SecondsSinceUnixEpoch::from_system_time(time).unwrap();
|
||||
assert!(session.expired());
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -24,7 +24,7 @@ use std::{
|
||||
};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use matrix_sdk_common::{instant::Instant, locks::Mutex};
|
||||
use matrix_sdk_common::{locks::Mutex, util::seconds_since_unix_epoch};
|
||||
use ruma::{
|
||||
events::{
|
||||
room::{
|
||||
@@ -37,7 +37,7 @@ use ruma::{
|
||||
room_key::ToDeviceRoomKeyEventContent,
|
||||
AnyToDeviceEventContent,
|
||||
},
|
||||
DeviceId, EventEncryptionAlgorithm, RoomId, TransactionId, UserId,
|
||||
DeviceId, EventEncryptionAlgorithm, RoomId, SecondsSinceUnixEpoch, TransactionId, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
@@ -49,7 +49,6 @@ pub use vodozemac::{
|
||||
PickleError,
|
||||
};
|
||||
|
||||
use super::super::{deserialize_instant, serialize_instant};
|
||||
use crate::{Device, ToDeviceRequest};
|
||||
|
||||
const ROTATION_PERIOD: Duration = Duration::from_millis(604800000);
|
||||
@@ -118,7 +117,7 @@ pub struct OutboundGroupSession {
|
||||
account_identity_keys: Arc<IdentityKeys>,
|
||||
session_id: Arc<str>,
|
||||
room_id: Arc<RoomId>,
|
||||
pub(crate) creation_time: Arc<Instant>,
|
||||
pub(crate) creation_time: SecondsSinceUnixEpoch,
|
||||
message_count: Arc<AtomicU64>,
|
||||
shared: Arc<AtomicBool>,
|
||||
invalidated: Arc<AtomicBool>,
|
||||
@@ -175,7 +174,7 @@ impl OutboundGroupSession {
|
||||
device_id,
|
||||
account_identity_keys: identity_keys,
|
||||
session_id: session_id.into(),
|
||||
creation_time: Arc::new(Instant::now()),
|
||||
creation_time: seconds_since_unix_epoch(),
|
||||
message_count: Arc::new(AtomicU64::new(0)),
|
||||
shared: Arc::new(AtomicBool::new(false)),
|
||||
invalidated: Arc::new(AtomicBool::new(false)),
|
||||
@@ -305,6 +304,18 @@ impl OutboundGroupSession {
|
||||
)
|
||||
}
|
||||
|
||||
fn elapsed(&self) -> bool {
|
||||
let creation_time = Duration::from_secs(self.creation_time.get().into());
|
||||
let now = Duration::from_secs(seconds_since_unix_epoch().get().into());
|
||||
|
||||
// Since the encryption settings are provided by users and not
|
||||
// checked someone could set a really low rotation period so
|
||||
// clamp it to an hour.
|
||||
now.checked_sub(creation_time)
|
||||
.map(|elapsed| elapsed >= max(self.settings.rotation_period, Duration::from_secs(3600)))
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
/// Check if the session has expired and if it should be rotated.
|
||||
///
|
||||
/// A session will expire after some time or if enough messages have been
|
||||
@@ -312,12 +323,7 @@ impl OutboundGroupSession {
|
||||
pub fn expired(&self) -> bool {
|
||||
let count = self.message_count.load(Ordering::SeqCst);
|
||||
|
||||
count >= self.settings.rotation_period_msgs
|
||||
|| self.creation_time.elapsed()
|
||||
// Since the encryption settings are provided by users and not
|
||||
// checked someone could set a really low rotation period so
|
||||
// clamp it to an hour.
|
||||
>= max(self.settings.rotation_period, Duration::from_secs(3600))
|
||||
count >= self.settings.rotation_period_msgs || self.elapsed()
|
||||
}
|
||||
|
||||
/// Has the session been invalidated.
|
||||
@@ -488,7 +494,7 @@ impl OutboundGroupSession {
|
||||
account_identity_keys: identity_keys,
|
||||
session_id: session_id.into(),
|
||||
room_id: pickle.room_id,
|
||||
creation_time: pickle.creation_time.into(),
|
||||
creation_time: pickle.creation_time,
|
||||
message_count: AtomicU64::from(pickle.message_count).into(),
|
||||
shared: AtomicBool::from(pickle.shared).into(),
|
||||
invalidated: AtomicBool::from(pickle.invalidated).into(),
|
||||
@@ -519,7 +525,7 @@ impl OutboundGroupSession {
|
||||
pickle,
|
||||
room_id: self.room_id.clone(),
|
||||
settings: self.settings.clone(),
|
||||
creation_time: *self.creation_time,
|
||||
creation_time: self.creation_time,
|
||||
message_count: self.message_count.load(Ordering::SeqCst),
|
||||
shared: self.shared(),
|
||||
invalidated: self.invalidated(),
|
||||
@@ -577,8 +583,7 @@ pub struct PickledOutboundGroupSession {
|
||||
/// The room id this session is used for.
|
||||
pub room_id: Arc<RoomId>,
|
||||
/// The timestamp when this session was created.
|
||||
#[serde(deserialize_with = "deserialize_instant", serialize_with = "serialize_instant")]
|
||||
pub creation_time: Instant,
|
||||
pub creation_time: SecondsSinceUnixEpoch,
|
||||
/// The number of messages this session has already encrypted.
|
||||
pub message_count: u64,
|
||||
/// Is the session shared.
|
||||
|
||||
@@ -30,33 +30,11 @@ pub use group_sessions::{
|
||||
EncryptionSettings, ExportedRoomKey, InboundGroupSession, OutboundGroupSession,
|
||||
PickledInboundGroupSession, PickledOutboundGroupSession, SessionKey, ShareInfo,
|
||||
};
|
||||
use matrix_sdk_common::instant::{Duration, Instant};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
pub use session::{PickledSession, Session};
|
||||
pub use signing::{CrossSigningStatus, PickledCrossSigningIdentity, PrivateCrossSigningIdentity};
|
||||
pub(crate) use utility::VerifyJson;
|
||||
pub use vodozemac::olm::IdentityKeys;
|
||||
|
||||
pub(crate) fn serialize_instant<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
let duration = instant.elapsed();
|
||||
duration.serialize(serializer)
|
||||
}
|
||||
|
||||
pub(crate) fn deserialize_instant<'de, D>(deserializer: D) -> Result<Instant, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
let duration = Duration::deserialize(deserializer)?;
|
||||
let now = Instant::now();
|
||||
let instant = now
|
||||
.checked_sub(duration)
|
||||
.ok_or_else(|| serde::de::Error::custom("Can't subtract the current instant"))?;
|
||||
Ok(instant)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod tests {
|
||||
use matches::assert_matches;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
use std::{collections::BTreeMap, fmt, sync::Arc};
|
||||
|
||||
use matrix_sdk_common::{instant::Instant, locks::Mutex};
|
||||
use matrix_sdk_common::{locks::Mutex, util::seconds_since_unix_epoch};
|
||||
use ruma::{
|
||||
events::{
|
||||
room::encrypted::{
|
||||
@@ -23,7 +23,7 @@ use ruma::{
|
||||
},
|
||||
AnyToDeviceEventContent, EventContent,
|
||||
},
|
||||
DeviceId, UserId,
|
||||
DeviceId, SecondsSinceUnixEpoch, UserId,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
@@ -32,7 +32,7 @@ use vodozemac::{
|
||||
Curve25519PublicKey,
|
||||
};
|
||||
|
||||
use super::{deserialize_instant, serialize_instant, IdentityKeys};
|
||||
use super::IdentityKeys;
|
||||
use crate::{
|
||||
error::{EventError, OlmResult},
|
||||
ReadOnlyDevice,
|
||||
@@ -57,9 +57,9 @@ pub struct Session {
|
||||
/// Has this been created using the fallback key
|
||||
pub created_using_fallback_key: bool,
|
||||
/// When the session was created
|
||||
pub creation_time: Arc<Instant>,
|
||||
pub creation_time: SecondsSinceUnixEpoch,
|
||||
/// When the session was last used
|
||||
pub last_use_time: Arc<Instant>,
|
||||
pub last_use_time: SecondsSinceUnixEpoch,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
@@ -83,7 +83,7 @@ impl Session {
|
||||
/// * `message` - The Olm message that should be decrypted.
|
||||
pub async fn decrypt(&mut self, message: &OlmMessage) -> Result<String, DecryptionError> {
|
||||
let plaintext = self.inner.lock().await.decrypt(message)?;
|
||||
self.last_use_time = Arc::new(Instant::now());
|
||||
self.last_use_time = seconds_since_unix_epoch();
|
||||
Ok(plaintext)
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ impl Session {
|
||||
/// * `plaintext` - The plaintext that should be encrypted.
|
||||
pub(crate) async fn encrypt_helper(&mut self, plaintext: &str) -> OlmMessage {
|
||||
let message = self.inner.lock().await.encrypt(plaintext);
|
||||
self.last_use_time = Arc::new(Instant::now());
|
||||
self.last_use_time = seconds_since_unix_epoch();
|
||||
message
|
||||
}
|
||||
|
||||
@@ -173,8 +173,8 @@ impl Session {
|
||||
pickle,
|
||||
sender_key: self.sender_key,
|
||||
created_using_fallback_key: self.created_using_fallback_key,
|
||||
creation_time: *self.creation_time,
|
||||
last_use_time: *self.last_use_time,
|
||||
creation_time: self.creation_time,
|
||||
last_use_time: self.last_use_time,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +212,8 @@ impl Session {
|
||||
session_id: session_id.into(),
|
||||
created_using_fallback_key: pickle.created_using_fallback_key,
|
||||
sender_key: pickle.sender_key,
|
||||
creation_time: Arc::new(pickle.creation_time),
|
||||
last_use_time: Arc::new(pickle.last_use_time),
|
||||
creation_time: pickle.creation_time,
|
||||
last_use_time: pickle.last_use_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,10 +238,8 @@ pub struct PickledSession {
|
||||
/// Was the session created using a fallback key.
|
||||
#[serde(default)]
|
||||
pub created_using_fallback_key: bool,
|
||||
/// The relative time elapsed since the session was created.
|
||||
#[serde(deserialize_with = "deserialize_instant", serialize_with = "serialize_instant")]
|
||||
pub creation_time: Instant,
|
||||
/// The relative time elapsed since the session was last used.
|
||||
#[serde(deserialize_with = "deserialize_instant", serialize_with = "serialize_instant")]
|
||||
pub last_use_time: Instant,
|
||||
/// The Unix timestamp when the session was created.
|
||||
pub creation_time: SecondsSinceUnixEpoch,
|
||||
/// The Unix timestamp when the session was last used.
|
||||
pub last_use_time: SecondsSinceUnixEpoch,
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use std::{
|
||||
};
|
||||
|
||||
use dashmap::{DashMap, DashSet};
|
||||
use matrix_sdk_common::util::seconds_since_unix_epoch;
|
||||
use ruma::{
|
||||
api::client::keys::claim_keys::v3::{
|
||||
Request as KeysClaimRequest, Response as KeysClaimResponse,
|
||||
@@ -83,7 +84,7 @@ impl SessionManager {
|
||||
|
||||
if let Some(sessions) = sessions {
|
||||
let mut sessions = sessions.lock().await;
|
||||
sessions.sort_by_key(|s| s.creation_time.clone());
|
||||
sessions.sort_by_key(|s| s.creation_time);
|
||||
|
||||
let session = sessions.get(0);
|
||||
|
||||
@@ -94,7 +95,15 @@ impl SessionManager {
|
||||
"Marking session to be unwedged"
|
||||
);
|
||||
|
||||
if session.creation_time.elapsed() > Self::UNWEDGING_INTERVAL {
|
||||
let creation_time = Duration::from_secs(session.creation_time.get().into());
|
||||
let now = Duration::from_secs(seconds_since_unix_epoch().get().into());
|
||||
|
||||
let should_unwedge = now
|
||||
.checked_sub(creation_time)
|
||||
.map(|elapsed| elapsed > Self::UNWEDGING_INTERVAL)
|
||||
.unwrap_or(true);
|
||||
|
||||
if should_unwedge {
|
||||
self.users_for_key_claim
|
||||
.entry(device.user_id().to_owned())
|
||||
.or_insert_with(DashSet::new)
|
||||
@@ -433,15 +442,16 @@ mod tests {
|
||||
#[async_test]
|
||||
#[cfg(target_os = "linux")]
|
||||
async fn session_unwedging() {
|
||||
use matrix_sdk_common::instant::{Duration, Instant};
|
||||
use ruma::DeviceKeyAlgorithm;
|
||||
use matrix_sdk_common::instant::{Duration, SystemTime};
|
||||
use ruma::{DeviceKeyAlgorithm, SecondsSinceUnixEpoch};
|
||||
|
||||
let manager = session_manager().await;
|
||||
let bob = bob_account();
|
||||
let (_, mut session) = bob.create_session_for(&manager.account).await;
|
||||
|
||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
||||
session.creation_time = Arc::new(Instant::now() - Duration::from_secs(3601));
|
||||
let time = SystemTime::now() - Duration::from_secs(3601);
|
||||
session.creation_time = SecondsSinceUnixEpoch::from_system_time(time).unwrap();
|
||||
|
||||
manager.store.save_devices(&[bob_device.clone()]).await.unwrap();
|
||||
manager.store.save_sessions(&[session]).await.unwrap();
|
||||
|
||||
Reference in New Issue
Block a user