[fractal/fractal-next] verification: Add timeout
- From: Julian Sparber <jsparber src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [fractal/fractal-next] verification: Add timeout
- Date: Thu, 13 Jan 2022 14:34:40 +0000 (UTC)
commit 15f2be9122132e612fcf7ccaa1f3c36fb31547e4
Author: Julian Sparber <julian sparber net>
Date: Sun Dec 26 17:03:43 2021 +0100
verification: Add timeout
src/session/verification/identity_verification.rs | 117 ++++++++++++++++++++--
src/session/verification/verification_list.rs | 82 +++++++++++----
2 files changed, 167 insertions(+), 32 deletions(-)
---
diff --git a/src/session/verification/identity_verification.rs
b/src/session/verification/identity_verification.rs
index c39b3072..4fbadc16 100644
--- a/src/session/verification/identity_verification.rs
+++ b/src/session/verification/identity_verification.rs
@@ -1,3 +1,4 @@
+use super::{VERIFICATION_CREATION_TIMEOUT, VERIFICATION_RECEIVE_TIMEOUT};
use crate::session::user::UserExt;
use crate::session::Session;
use crate::session::User;
@@ -23,6 +24,7 @@ use matrix_sdk::{
Client,
};
use qrcode::QrCode;
+use std::time::Duration;
use tokio::sync::mpsc;
#[derive(Debug, Eq, PartialEq, Clone, Copy, glib::GEnum)]
@@ -118,6 +120,8 @@ mod imp {
pub qr_code: OnceCell<QrCode>,
pub cancel_info: OnceCell<CancelInfo>,
pub flow_id: OnceCell<String>,
+ pub start_time: OnceCell<glib::DateTime>,
+ pub receive_time: OnceCell<glib::DateTime>,
}
#[glib::object_subclass]
@@ -175,6 +179,20 @@ mod imp {
None,
glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
),
+ glib::ParamSpec::new_boxed(
+ "start-time",
+ "Start Time",
+ "The time when this verification request was started",
+ glib::DateTime::static_type(),
+ glib::ParamFlags::READWRITE | glib::ParamFlags::CONSTRUCT_ONLY,
+ ),
+ glib::ParamSpec::new_boxed(
+ "receive-time",
+ "Receive Time",
+ "The time when this verification request was received",
+ glib::DateTime::static_type(),
+ glib::ParamFlags::READABLE,
+ ),
]
});
@@ -192,6 +210,7 @@ mod imp {
"user" => obj.set_user(value.get().unwrap()),
"session" => obj.set_session(value.get().unwrap()),
"flow-id" => obj.set_flow_id(value.get().unwrap()),
+ "start-time" => obj.set_start_time(value.get().unwrap()),
_ => unimplemented!(),
}
}
@@ -204,6 +223,8 @@ mod imp {
"display-name" => obj.display_name().to_value(),
"flow-id" => obj.flow_id().to_value(),
"supported-methods" => obj.supported_methods().to_value(),
+ "start-time" => obj.start_time().to_value(),
+ "receive-time" => obj.receive_time().to_value(),
_ => unimplemented!(),
}
}
@@ -241,6 +262,11 @@ mod imp {
}),
);
}
+
+ self.receive_time
+ .set(glib::DateTime::new_now_local().unwrap())
+ .unwrap();
+ obj.setup_timeout();
}
fn dispose(&self, obj: &Self::Type) {
@@ -254,15 +280,30 @@ glib::wrapper! {
}
impl IdentityVerification {
- fn for_mode(mode: Mode, session: &Session, user: &User) -> Self {
- glib::Object::new(&[("mode", &mode), ("session", session), ("user", user)])
- .expect("Failed to create IdentityVerification")
+ fn for_mode(mode: Mode, session: &Session, user: &User, start_time: &glib::DateTime) -> Self {
+ glib::Object::new(&[
+ ("mode", &mode),
+ ("session", session),
+ ("user", user),
+ ("start-time", start_time),
+ ])
+ .expect("Failed to create IdentityVerification")
}
/// Create a new object tracking an already existing verification request
- pub fn for_flow_id(flow_id: &str, session: &Session, user: &User) -> Self {
- glib::Object::new(&[("flow-id", &flow_id), ("session", session), ("user", user)])
- .expect("Failed to create IdentityVerification")
+ pub fn for_flow_id(
+ flow_id: &str,
+ session: &Session,
+ user: &User,
+ start_time: &glib::DateTime,
+ ) -> Self {
+ glib::Object::new(&[
+ ("flow-id", &flow_id),
+ ("session", session),
+ ("user", user),
+ ("start-time", start_time),
+ ])
+ .expect("Failed to create IdentityVerification")
}
/// Creates and send a new verificaiton request
@@ -281,7 +322,12 @@ impl IdentityVerification {
match handle.await.unwrap() {
Ok(request) => {
- let obj = Self::for_flow_id(request.flow_id(), session, user);
+ let obj = Self::for_flow_id(
+ request.flow_id(),
+ session,
+ user,
+ &glib::DateTime::new_now_local().unwrap(),
+ );
// This will start the request handling
obj.accept();
return obj;
@@ -294,7 +340,12 @@ impl IdentityVerification {
error!("Starting a verification failed: Crypto identity wasn't found");
}
- Self::for_mode(Mode::Error, session, user)
+ Self::for_mode(
+ Mode::Error,
+ session,
+ user,
+ &glib::DateTime::new_now_local().unwrap(),
+ )
}
/// Accept an incomming request
@@ -315,8 +366,6 @@ impl IdentityVerification {
let (sync_sender, sync_receiver) = mpsc::channel(100);
priv_.sync_sender.replace(Some(sync_sender));
- // TODO add timeout
-
let handle = spawn_tokio!(async move {
if let Some(context) =
Context::new(client, &user_id, &flow_id, main_sender, sync_receiver).await
@@ -367,6 +416,54 @@ impl IdentityVerification {
priv_.session.set(session.downgrade()).unwrap()
}
+ fn setup_timeout(&self) {
+ let difference = glib::DateTime::new_now_local()
+ .unwrap()
+ .difference(self.start_time());
+
+ if difference < 0 {
+ warn!("The verification request was sent in the future.");
+ self.cancel();
+ return;
+ }
+ let difference = Duration::from_secs(difference as u64);
+ let remaining_creation = VERIFICATION_CREATION_TIMEOUT.saturating_sub(difference);
+
+ let remaining_receive = VERIFICATION_RECEIVE_TIMEOUT.saturating_sub(difference);
+
+ let remaining = std::cmp::max(remaining_creation, remaining_receive);
+
+ if remaining.is_zero() {
+ self.cancel();
+ return;
+ }
+
+ glib::source::timeout_add_local(
+ remaining,
+ clone!(@weak self as obj => @default-return glib::Continue(false), move || {
+ obj.cancel();
+
+ glib::Continue(false)
+ }),
+ );
+ }
+
+ /// The time and date when this verification request was started.
+ pub fn start_time(&self) -> &glib::DateTime {
+ let priv_ = imp::IdentityVerification::from_instance(self);
+ priv_.start_time.get().unwrap()
+ }
+
+ fn set_start_time(&self, time: glib::DateTime) {
+ let priv_ = imp::IdentityVerification::from_instance(self);
+ priv_.start_time.set(time).unwrap();
+ }
+
+ pub fn receive_time(&self) -> &glib::DateTime {
+ let priv_ = imp::IdentityVerification::from_instance(self);
+ priv_.receive_time.get().unwrap()
+ }
+
fn supported_methods(&self) -> SupportedMethods {
let priv_ = imp::IdentityVerification::from_instance(self);
priv_.supported_methods.get()
diff --git a/src/session/verification/verification_list.rs b/src/session/verification/verification_list.rs
index 5b3290ba..8363fb4d 100644
--- a/src/session/verification/verification_list.rs
+++ b/src/session/verification/verification_list.rs
@@ -1,11 +1,14 @@
use crate::session::user::UserExt;
+use crate::session::{
+ verification::{IdentityVerification, VERIFICATION_CREATION_TIMEOUT},
+ Session,
+};
use gtk::{gio, glib, glib::clone, prelude::*, subclass::prelude::*};
+use log::warn;
use matrix_sdk::ruma::{
api::client::r0::sync::sync_events::ToDevice, events::AnyToDeviceEvent, identifiers::UserId,
};
-use crate::session::{verification::IdentityVerification, Session};
-
#[derive(Hash, PartialEq, Eq, Debug)]
pub struct FlowId {
user_id: UserId,
@@ -112,46 +115,81 @@ impl VerificationList {
pub fn handle_response_to_device(&self, to_device: ToDevice) {
for event in to_device.events.iter().filter_map(|e| e.deserialize().ok()) {
- let flow_id = match event {
+ let request = match event {
AnyToDeviceEvent::KeyVerificationRequest(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ let flow_id = FlowId::new(e.sender, e.content.transaction_id);
+ if let Some(request) = self.get_by_id(&flow_id) {
+ Some(request)
+ } else {
+ let session = self.session();
+ let user = session.user().unwrap();
+ // ToDevice verifications can only be send by us
+ if &flow_id.user_id != user.user_id() {
+ continue;
+ }
+
+ // Ignore request that are too old
+ let start_time = if let Some(time) = e.content.timestamp.to_system_time() {
+ if let Ok(duration) = time.elapsed() {
+ if duration > VERIFICATION_CREATION_TIMEOUT {
+ continue;
+ }
+
+ if let Ok(time) = glib::DateTime::from_unix_utc(
+ e.content.timestamp.as_secs().into(),
+ )
+ .and_then(|t| t.to_local())
+ {
+ time
+ } else {
+ warn!("Ignor verification request because getting a correct timestamp
failed");
+ continue;
+ }
+ } else {
+ warn!("Ignoring verification request because it was sent in the future. The
system time of the server or the local machine is probably wrong.");
+ continue;
+ }
+ } else {
+ continue;
+ };
+
+ let request = IdentityVerification::for_flow_id(
+ &flow_id.flow_id,
+ &session,
+ user,
+ &start_time,
+ );
+ self.add(request.clone());
+ Some(request)
+ }
}
AnyToDeviceEvent::KeyVerificationReady(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationStart(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationCancel(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationAccept(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationMac(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationKey(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
AnyToDeviceEvent::KeyVerificationDone(e) => {
- FlowId::new(e.sender, e.content.transaction_id)
+ self.get_by_id(&FlowId::new(e.sender, e.content.transaction_id))
}
_ => continue,
};
-
- if let Some(request) = self.get_by_id(&flow_id) {
+ if let Some(request) = request {
request.notify_state();
} else {
- let session = self.session();
- let user = session.user().unwrap();
- // ToDevice verifications can only be send by us
- if &flow_id.user_id == user.user_id() {
- let request =
- IdentityVerification::for_flow_id(&flow_id.flow_id, &session, user);
- request.notify_state();
- self.add(request);
- }
+ warn!("Recevied verification event, but we don't have the inital event.");
}
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]