diff --git a/Cargo.lock b/Cargo.lock index e9be84f7f4..451884c793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6944,7 +6944,6 @@ dependencies = [ "anyhow", "derive_builder", "rustversion", - "time", "vergen-lib", ] diff --git a/crates/defguard_common/Cargo.toml b/crates/defguard_common/Cargo.toml index f90b8750a0..12f0bbe1df 100644 --- a/crates/defguard_common/Cargo.toml +++ b/crates/defguard_common/Cargo.toml @@ -45,4 +45,4 @@ url = "2.5" matches.workspace = true [build-dependencies] -vergen-git2 = { version = "9.1", features = ["build"] } +vergen-git2 = "9.1" diff --git a/crates/defguard_common/build.rs b/crates/defguard_common/build.rs index d1e71d8bbe..aa2933073b 100644 --- a/crates/defguard_common/build.rs +++ b/crates/defguard_common/build.rs @@ -2,7 +2,7 @@ use vergen_git2::{Emitter, Git2Builder}; fn main() -> Result<(), Box> { // set VERGEN_GIT_SHA env variable based on git commit hash - let git2 = Git2Builder::default().branch(true).sha(true).build()?; + let git2 = Git2Builder::default().sha(true).build()?; Emitter::default().add_instructions(&git2)?.emit()?; println!("cargo:rerun-if-changed=../../migrations"); diff --git a/crates/defguard_core/src/handlers/mail.rs b/crates/defguard_core/src/handlers/mail.rs index d21ad0767f..54c5e2e3d6 100644 --- a/crates/defguard_core/src/handlers/mail.rs +++ b/crates/defguard_core/src/handlers/mail.rs @@ -192,14 +192,13 @@ pub async fn send_gateway_disconnected_email( } pub async fn send_gateway_reconnected_email( - gateway_name: Option, + gateway_name: String, network_name: String, gateway_adress: &str, pool: &PgPool, ) -> Result<(), WebError> { debug!("Sending gateway reconnect mail to all admin users"); let admin_users = User::find_admins(pool).await?; - let gateway_name = gateway_name.unwrap_or_default(); for user in admin_users { Mail::new( &user.email, diff --git a/crates/defguard_gateway_manager/src/handler.rs b/crates/defguard_gateway_manager/src/handler.rs index f086ee35a5..fb4ad257b5 100644 --- a/crates/defguard_gateway_manager/src/handler.rs +++ b/crates/defguard_gateway_manager/src/handler.rs @@ -8,7 +8,7 @@ use std::{ }, }; -use chrono::DateTime; +use chrono::{DateTime, TimeDelta}; use defguard_common::{ VERSION, db::{ @@ -18,8 +18,9 @@ use defguard_common::{ messages::peer_stats_update::PeerStatsUpdate, }; use defguard_core::{ - enterprise::firewall::try_get_location_firewall_config, grpc::GatewayEvent, - handlers::mail::send_gateway_disconnected_email, + enterprise::firewall::try_get_location_firewall_config, + grpc::GatewayEvent, + handlers::mail::{send_gateway_disconnected_email, send_gateway_reconnected_email}, location_management::allowed_peers::get_location_allowed_peers, }; #[cfg(not(test))] @@ -163,7 +164,7 @@ impl GatewayHandler { } } - /// Send gateway disconnected notification. + /// Send Gateway disconnected notification. /// Sends notification only if last notification time is bigger than specified in config. async fn send_disconnect_notification(&self) { let settings = Settings::get_current_settings(); @@ -171,7 +172,17 @@ impl GatewayHandler { return; } - debug!("Sending gateway disconnect email notification"); + // Send email only if disconnection time is before the connection time. + if let (Some(connected_at), Some(disconnected_at)) = + (self.gateway.connected_at, self.gateway.disconnected_at) + { + if disconnected_at > connected_at { + info!("{} disconnected; email notification not sent", self.gateway); + return; + } + }; + + debug!("Sending Gateway disconnect email notification"); let name = self.gateway.name.clone(); let pool = self.pool.clone(); let url = format!("{}:{}", self.gateway.address, self.gateway.port); @@ -186,32 +197,51 @@ impl GatewayHandler { return; }; - // Send email only if disconnection time is before the connection time. - let send_email = if let (Some(connected_at), Some(disconnected_at)) = + // FIXME: Try to get rid of spawn and use something like block_on + // To return result instead of logging + tokio::spawn(async move { + if let Err(err) = send_gateway_disconnected_email(name, network.name, &url, &pool).await + { + error!("Failed to send Gateway disconnect notification: {err}"); + } else { + info!("Sent email notification about Gateway being disconnected"); + } + }); + } + + /// Send Gateway reconnected notification. + fn send_reconnect_notification(&self, network_name: String) { + let settings = Settings::get_current_settings(); + if !settings.gateway_disconnect_notifications_reconnect_notification_enabled { + return; + } + + let (Some(connected_at), Some(disconnected_at)) = (self.gateway.connected_at, self.gateway.disconnected_at) - { - disconnected_at <= connected_at - } else { - true + else { + return; }; - if send_email { - // FIXME: Try to get rid of spawn and use something like block_on - // To return result instead of logging - tokio::spawn(async move { - if let Err(err) = - send_gateway_disconnected_email(name, network.name, &url, &pool).await - { - error!("Failed to send gateway disconnect notification: {err}"); - } else { - info!("Email notification sent about gateway being disconnected"); - } - }); - } else { - info!( - "{} disconnected. Email notification not sent.", - self.gateway - ); + let inactivity_threshold = TimeDelta::minutes(i64::from( + settings.gateway_disconnect_notifications_inactivity_threshold, + )); + if connected_at - disconnected_at <= inactivity_threshold { + return; } + + debug!("Sending Gateway reconnect email notification"); + let gateway_name = self.gateway.name.clone(); + let pool = self.pool.clone(); + let url = format!("{}:{}", self.gateway.address, self.gateway.port); + + tokio::spawn(async move { + if let Err(err) = + send_gateway_reconnected_email(gateway_name, network_name, &url, &pool).await + { + error!("Failed to send Gateway reconnect notification: {err}"); + } else { + info!("Sent email notification about Gateway being reconnected"); + } + }); } /// Connect to Gateway and handle its messages through gRPC. @@ -308,7 +338,19 @@ impl GatewayHandler { Ok(network) => { info!("Sent configuration to {}", self.gateway); config_sent = true; - let _ = self.gateway.touch_connected(&self.pool).await; + match self.gateway.touch_connected(&self.pool).await { + Ok(()) => { + self.send_reconnect_notification( + network.name.clone(), + ); + } + Err(err) => { + error!( + "Failed to update connection time for {} in the database: {err}", + self.gateway + ); + } + } let mut updates_handler = GatewayUpdatesHandler::new( self.gateway.location_id, network,