From 4e9cf6aa004e810a8818c9f419098c8c21b01d95 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Thu, 5 Oct 2023 18:09:25 +0200 Subject: [PATCH 1/8] log trait --- src-tauri/src/commands.rs | 81 ++++++++++++++++++++++++----------- src-tauri/src/database/mod.rs | 18 +++++--- src-tauri/src/utils.rs | 36 +++++++++++++--- 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 983c42f4..6cbadbb1 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -3,7 +3,7 @@ use crate::{ models::{instance::InstanceInfo, location::peer_to_location_stats}, Connection, ConnectionInfo, Instance, Location, LocationStats, WireguardKeys, }, - utils::{remove_whitespace, setup_interface, IS_MACOS}, + utils::{remove_whitespace, setup_interface, LogExt, IS_MACOS}, AppState, }; use chrono::Utc; @@ -25,7 +25,8 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S let state = handle.state::(); if let Some(location) = Location::find_by_id(&state.get_pool(), location_id) .await - .map_err(|err| err.to_string())? + .map_err(|err| err.to_string()) + .log()? { debug!( "Creating new interface connection for location: {}", @@ -33,8 +34,9 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S ); let api = setup_interface(&location, &state.get_pool()) .await - .map_err(|err| err.to_string())?; - let address = local_ip().map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; + let address = local_ip().map_err(|err| err.to_string()).log()?; let connection = Connection::new(location_id, address.to_string()); state.active_connections.lock().unwrap().push(connection); debug!( @@ -62,6 +64,7 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S peer_to_location_stats(&peer, &state.get_pool()) .await .map_err(|err| err.to_string()) + .log() .unwrap(); debug!("Saving location stats: {:#?}", location_stats); let _ = location_stats.save(&state.get_pool()).await; @@ -94,12 +97,16 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() let state = handle.state::(); if let Some(location) = Location::find_by_id(&state.get_pool(), location_id) .await - .map_err(|err| err.to_string())? + .map_err(|err| err.to_string()) + .log()? { - let api = - WGApi::new(remove_whitespace(&location.name), IS_MACOS).map_err(|e| e.to_string())?; + let api = WGApi::new(remove_whitespace(&location.name), IS_MACOS) + .map_err(|e| e.to_string()) + .log()?; debug!("Removing interface"); - api.remove_interface().map_err(|err| err.to_string())?; + api.remove_interface() + .map_err(|err| err.to_string()) + .log()?; debug!("Removed interface"); if let Some(mut connection) = state.find_and_remove_connection(location_id) { debug!("Saving connection: {:#?}", connection); @@ -107,7 +114,8 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() connection .save(&state.get_pool()) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; debug!("Saved connection: {:#?}", connection); } handle @@ -179,7 +187,8 @@ pub async fn save_device_config( .get_pool() .begin() .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; let mut instance = Instance::new( response.instance.name, response.instance.id, @@ -188,7 +197,8 @@ pub async fn save_device_config( instance .save(&mut *transaction) .await - .map_err(|e| e.to_string())?; + .map_err(|e| e.to_string()) + .log()?; let mut keys = WireguardKeys::new(instance.id.unwrap(), response.device.pubkey, private_key); keys.save(&mut *transaction) .await @@ -198,14 +208,20 @@ pub async fn save_device_config( new_location .save(&mut *transaction) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; } - transaction.commit().await.map_err(|err| err.to_string())?; + transaction + .commit() + .await + .map_err(|err| err.to_string()) + .log()?; info!("Instance created."); debug!("Created following instance: {:#?}", instance); let locations = Location::find_by_instance_id(&app_state.get_pool(), instance.id.unwrap()) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; debug!("Created following locations: {:#?}", locations); Ok(()) } @@ -215,14 +231,16 @@ pub async fn all_instances(app_state: State<'_, AppState>) -> Result = vec![]; for instance in &instances { debug!("Checking if instance: {:#?} is active", instance.uuid); let locations = Location::find_by_instance_id(&app_state.get_pool(), instance.id.unwrap()) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; let connection_ids: Vec = app_state .active_connections .lock() @@ -239,7 +257,8 @@ pub async fn all_instances(app_state: State<'_, AppState>) -> Result = app_state .active_connections .lock() @@ -307,13 +327,15 @@ pub async fn update_instance( debug!("Received following response: {:#?}", response); let instance = Instance::find_by_id(&app_state.get_pool(), instance_id) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; if let Some(mut instance) = instance { let mut transaction = app_state .get_pool() .begin() .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; instance.name = response.instance.name; instance.url = response.instance.url; instance @@ -326,7 +348,8 @@ pub async fn update_instance( let old_location = Location::find_by_native_id(&mut *transaction, new_location.network_id) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; if let Some(mut old_location) = old_location { old_location.name = new_location.name; old_location.address = new_location.address; @@ -336,15 +359,21 @@ pub async fn update_instance( old_location .save(&mut *transaction) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; } else { new_location .save(&mut *transaction) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; } } - transaction.commit().await.map_err(|err| err.to_string())?; + transaction + .commit() + .await + .map_err(|err| err.to_string()) + .log()?; info!("Updated instance with id: {}.", instance_id); Ok(()) } else { @@ -359,6 +388,7 @@ pub async fn location_stats( LocationStats::all_by_location_id(&app_state.get_pool(), location_id) .await .map_err(|err| err.to_string()) + .log() } #[tauri::command] @@ -369,7 +399,8 @@ pub async fn all_connections( debug!("Retrieving all conections."); let connections = ConnectionInfo::all_by_location_id(&app_state.get_pool(), location_id) .await - .map_err(|err| err.to_string())?; + .map_err(|err| err.to_string()) + .log()?; debug!( "Returning all connections for location with id: {}, {:#?} ", location_id, connections diff --git a/src-tauri/src/database/mod.rs b/src-tauri/src/database/mod.rs index 11c1749b..36a55bf9 100644 --- a/src-tauri/src/database/mod.rs +++ b/src-tauri/src/database/mod.rs @@ -1,5 +1,6 @@ pub mod models; +use crate::utils::LogExt; use std::fs; use tauri::AppHandle; @@ -13,10 +14,11 @@ pub async fn init_db(app_handle: &AppHandle) -> Result { let app_dir = app_handle .path_resolver() .app_data_dir() - .ok_or(Error::Config)?; + .ok_or(Error::Config) + .log()?; // Create app data directory if it doesnt exist debug!("Creating app data dir at: {}", app_dir.to_string_lossy()); - fs::create_dir_all(&app_dir)?; + fs::create_dir_all(&app_dir).log()?; info!("Created app data dir at: {}", app_dir.to_string_lossy()); let db_path = app_dir.join(DB_NAME); if !db_path.exists() { @@ -24,7 +26,7 @@ pub async fn init_db(app_handle: &AppHandle) -> Result { "Database not found creating database file at: {}", db_path.to_string_lossy() ); - fs::File::create(&db_path)?; + fs::File::create(&db_path).log()?; info!( "Database file succesfully created at: {}", db_path.to_string_lossy() @@ -36,21 +38,23 @@ pub async fn init_db(app_handle: &AppHandle) -> Result { ); } debug!("Connecting to database: {}", db_path.to_string_lossy()); - let pool = DbPool::connect(&format!("sqlite://{}", db_path.to_str().unwrap())).await?; + let pool = DbPool::connect(&format!("sqlite://{}", db_path.to_str().unwrap())) + .await + .log()?; debug!("Running migrations."); - sqlx::migrate!().run(&pool).await?; + sqlx::migrate!().run(&pool).await.log()?; info!("Applied migrations."); Ok(pool) } pub async fn info(pool: &DbPool) -> Result<(), Error> { debug!("Following locations and instances are saved."); - let instances = Instance::all(pool).await?; + let instances = Instance::all(pool).await.log()?; debug!( "All instances found in database during start: {:#?}", instances ); - let locations = Location::all(pool).await?; + let locations = Location::all(pool).await.log()?; debug!( "All locations found in database during start: {:#?}", locations diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index d1d87bdc..2bcf010c 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,5 +1,6 @@ use std::{ net::{SocketAddr, TcpListener}, + panic::Location as ErrorLocation, str::FromStr, }; @@ -17,17 +18,22 @@ pub static IS_MACOS: bool = cfg!(target_os = "macos"); /// Setup client interface pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result { let interface_name = remove_whitespace(&location.name); - debug!("Creating new interface: {}", interface_name); - let api = create_api(&interface_name)?; + debug!( + "Creating new interface: {} for location: {:#?}", + interface_name, location + ); + let api = create_api(&interface_name).log()?; - api.create_interface()?; + api.create_interface().log()?; if let Some(keys) = WireguardKeys::find_by_instance_id(pool, location.instance_id).await? { // TODO: handle unwrap - let peer_key: Key = Key::from_str(&location.pubkey).unwrap(); + debug!("Decoding location public key."); + let peer_key: Key = Key::from_str("fewfwe").log()?; let mut peer = Peer::new(peer_key); debug!("Creating interface for location: {:#?}", location); - let endpoint: SocketAddr = location.endpoint.parse().unwrap(); + debug!("Setting up location endpoint: {}", location.endpoint); + let endpoint: SocketAddr = location.endpoint.parse().log()?; peer.endpoint = Some(endpoint); peer.persistent_keepalive_interval = Some(25); let allowed_ips: Vec = location @@ -83,7 +89,7 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result bool { pub fn create_api(interface_name: &str) -> Result { Ok(WGApi::new(interface_name.to_string(), IS_MACOS)?) } + +pub trait LogExt { + fn log(self) -> Self; +} +/// Trait to know when mapped error failed and how +/// example use failing_function().log()?; +impl LogExt for Result +where + E: std::fmt::Display, +{ + #[track_caller] + fn log(self) -> Self { + if let Err(e) = &self { + error!("Error '{e}' originated in :{}", &ErrorLocation::caller()); + } + self + } +} From c6d5aced86816f8000271c1eddfa460bfd0e0d35 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 08:58:56 +0200 Subject: [PATCH 2/8] add more logs --- src-tauri/src/utils.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 2bcf010c..94a1339b 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -28,14 +28,15 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result = location .allowed_ips .split(',') @@ -46,12 +47,12 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result { peer.allowed_ips.push(addr); - // TODO: Handle windows later + // TODO: Handle windows when wireguard_rs adds support // Add a route for the allowed IP using the `ip -4 route add` command if let Err(err) = add_route(&allowed_ip, &interface_name) { error!("Error adding route for {}: {}", allowed_ip, err); } else { - info!("Added route for {}", allowed_ip); + debug!("Added route for {}", allowed_ip); } } Err(err) => { From bfd301865464c02b94be197abcc1cc2803af66d3 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 09:23:02 +0200 Subject: [PATCH 3/8] Rename trait --- src-tauri/src/commands.rs | 2 +- src-tauri/src/database/mod.rs | 2 +- src-tauri/src/utils.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index f30a07db..0ccd807c 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -3,7 +3,7 @@ use crate::{ models::{instance::InstanceInfo, location::peer_to_location_stats}, Connection, ConnectionInfo, Instance, Location, LocationStats, WireguardKeys, }, - utils::{remove_whitespace, setup_interface, LogExt, IS_MACOS}, + utils::{remove_whitespace, setup_interface, LogError, IS_MACOS}, AppState, }; use chrono::Utc; diff --git a/src-tauri/src/database/mod.rs b/src-tauri/src/database/mod.rs index 36a55bf9..4bef6494 100644 --- a/src-tauri/src/database/mod.rs +++ b/src-tauri/src/database/mod.rs @@ -1,6 +1,6 @@ pub mod models; -use crate::utils::LogExt; +use crate::utils::LogError; use std::fs; use tauri::AppHandle; diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 94a1339b..268f217a 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -153,12 +153,12 @@ pub fn create_api(interface_name: &str) -> Result { Ok(WGApi::new(interface_name.to_string(), IS_MACOS)?) } -pub trait LogExt { +pub trait LogError { fn log(self) -> Self; } /// Trait to know when mapped error failed and how /// example use failing_function().log()?; -impl LogExt for Result +impl LogError for Result where E: std::fmt::Display, { From 739823a1a2982d2bef1c4ea08f9cb7401e3ebb77 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 10:11:56 +0200 Subject: [PATCH 4/8] wip --- src-tauri/src/appstate.rs | 11 +-- src-tauri/src/commands.rs | 17 +++-- src-tauri/src/database/mod.rs | 2 +- src-tauri/src/database/models/connection.rs | 54 ++++++++++++--- src-tauri/src/utils.rs | 75 ++++++++++++++++++--- 5 files changed, 126 insertions(+), 33 deletions(-) diff --git a/src-tauri/src/appstate.rs b/src-tauri/src/appstate.rs index c6e99200..72e544f3 100644 --- a/src-tauri/src/appstate.rs +++ b/src-tauri/src/appstate.rs @@ -1,17 +1,20 @@ use std::sync::{Arc, Mutex}; -use crate::database::{Connection, DbPool}; +use crate::database::{ActiveConnection, DbPool}; #[derive(Default)] pub struct AppState { pub db: Arc>>, - pub active_connections: Arc>>, + pub active_connections: Arc>>, } impl AppState { pub fn get_pool(&self) -> DbPool { self.db.lock().unwrap().as_ref().cloned().unwrap() } - pub fn find_and_remove_connection(&self, location_id: i64) -> Option { + pub fn get_connections(&self) -> Vec { + self.active_connections.lock().unwrap().clone() + } + pub fn find_and_remove_connection(&self, location_id: i64) -> Option { debug!( "Removing active connection for location with id: {}", location_id @@ -33,7 +36,7 @@ impl AppState { None // Connection not found } } - pub fn find_connection(&self, location_id: i64) -> Option { + pub fn find_connection(&self, location_id: i64) -> Option { let connections = self.active_connections.lock().unwrap(); debug!("Checking for active connection with location id: {location_id} in active connections: {:#?}", connections); diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 0ccd807c..2149b75a 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -1,9 +1,10 @@ use crate::{ database::{ models::{instance::InstanceInfo, location::peer_to_location_stats}, - Connection, ConnectionInfo, Instance, Location, LocationStats, WireguardKeys, + ActiveConnection, Connection, ConnectionInfo, Instance, Location, LocationStats, + WireguardKeys, }, - utils::{remove_whitespace, setup_interface, LogError, IS_MACOS}, + utils::{get_interface_name, remove_whitespace, setup_interface, LogError, IS_MACOS}, AppState, }; use chrono::Utc; @@ -32,12 +33,13 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), S "Creating new interface connection for location: {}", location.name ); - let api = setup_interface(&location, &state.get_pool()) + let interface_name = get_interface_name(&location, state.get_connections()); + let api = setup_interface(&location, &interface_name, &state.get_pool()) .await .map_err(|err| err.to_string()) .log()?; let address = local_ip().map_err(|err| err.to_string()).log()?; - let connection = Connection::new(location_id, address.to_string()); + let connection = ActiveConnection::new(location_id, address.to_string(), interface_name); state.active_connections.lock().unwrap().push(connection); debug!( "Active connections: {:#?}", @@ -100,6 +102,7 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() .map_err(|err| err.to_string()) .log()? { + let interface_name: String = state.get_connections().iter().map(|conn| con.loca) let api = WGApi::new(remove_whitespace(&location.name), IS_MACOS) .map_err(|e| e.to_string()) .log()?; @@ -108,9 +111,9 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() .map_err(|err| err.to_string()) .log()?; debug!("Removed interface"); - if let Some(mut connection) = state.find_and_remove_connection(location_id) { + if let Some(connection) = state.find_and_remove_connection(location_id) { debug!("Saving connection: {:#?}", connection); - connection.end = Some(Utc::now().naive_utc()); // Get the current time as NaiveDateTime in UTC + let mut connection: Connection = connection.into(); connection .save(&state.get_pool()) .await @@ -411,7 +414,7 @@ pub async fn all_connections( pub async fn active_connection( location_id: i64, handle: tauri::AppHandle, -) -> Result, String> { +) -> Result, String> { let state = handle.state::(); debug!( "Retrieving active connection for location with id: {}", diff --git a/src-tauri/src/database/mod.rs b/src-tauri/src/database/mod.rs index 4bef6494..4cd69523 100644 --- a/src-tauri/src/database/mod.rs +++ b/src-tauri/src/database/mod.rs @@ -63,7 +63,7 @@ pub async fn info(pool: &DbPool) -> Result<(), Error> { } pub use models::{ - connection::{Connection, ConnectionInfo}, + connection::{ActiveConnection, Connection, ConnectionInfo}, instance::{Instance, InstanceInfo}, location::{Location, LocationStats}, wireguard_keys::WireguardKeys, diff --git a/src-tauri/src/database/models/connection.rs b/src-tauri/src/database/models/connection.rs index 8486de79..eb6ec043 100644 --- a/src-tauri/src/database/models/connection.rs +++ b/src-tauri/src/database/models/connection.rs @@ -1,4 +1,5 @@ use chrono::{NaiveDateTime, Utc}; +use defguard_wireguard_rs::WGApi; use serde::Serialize; use sqlx::{query, query_as, FromRow}; @@ -10,20 +11,20 @@ pub struct Connection { pub location_id: i64, pub connected_from: String, pub start: NaiveDateTime, - pub end: Option, + pub end: NaiveDateTime, } impl Connection { - pub fn new(location_id: i64, connected_from: String) -> Self { - let start = Utc::now().naive_utc(); // Get the current time as NaiveDateTime in UTC - Connection { - id: None, - location_id, - connected_from, - start, - end: None, - } - } + //pub fn new(location_id: i64, connected_from: String) -> Self { + //let start = Utc::now().naive_utc(); // Get the current time as NaiveDateTime in UTC + //Connection { + //id: None, + //location_id, + //connected_from, + //start, + //end: None, + //} + //} pub async fn save(&mut self, pool: &DbPool) -> Result<(), Error> { let result = query!( @@ -121,3 +122,34 @@ impl ConnectionInfo { Ok(connections) } } + +#[derive(Debug, Serialize, Clone)] +pub struct ActiveConnection { + pub location_id: i64, + pub connected_from: String, + pub start: NaiveDateTime, + pub interface_name: String, +} +impl ActiveConnection { + pub fn new(location_id: i64, connected_from: String, interface_name: String) -> Self { + let start = Utc::now().naive_utc(); // Get the current time as NaiveDateTime in UTC + Self { + location_id, + connected_from, + start, + interface_name, + } + } +} + +impl From for Connection { + fn from(active_connection: ActiveConnection) -> Self { + Connection { + id: None, // Assuming you want to set it to None for new conversions + location_id: active_connection.location_id, + connected_from: active_connection.connected_from, + start: active_connection.start, + end: Utc::now().naive_utc(), + } + } +} diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 268f217a..d6d713b0 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -9,24 +9,27 @@ use defguard_wireguard_rs::{ }; use crate::{ - database::{DbPool, Location, WireguardKeys}, + database::{ActiveConnection, DbPool, Location, WireguardKeys}, error::Error, }; -pub static IS_MACOS: bool = cfg!(target_os = "macos"); +pub static IS_MACOS: bool = true; /// Setup client interface -pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result { - let interface_name = remove_whitespace(&location.name); +pub async fn setup_interface( + location: &Location, + interface_name: &str, + pool: &DbPool, +) -> Result { debug!( "Creating new interface: {} for location: {:#?}", interface_name, location ); - let api = create_api(&interface_name).log()?; - - api.create_interface().log()?; if let Some(keys) = WireguardKeys::find_by_instance_id(pool, location.instance_id).await? { + let api = create_api(&interface_name).log()?; + + api.create_interface().log()?; // TODO: handle unwrap debug!("Decoding location public key: {}.", location.pubkey); let peer_key: Key = Key::from_str(&location.pubkey).unwrap(); @@ -65,7 +68,7 @@ pub async fn setup_interface(location: &Location, pool: &DbPool) -> Result Result Option { None // No free port found in the specified range } +/// Returns interface name for location +pub fn get_interface_name( + location: &Location, + active_connections: Vec, +) -> String { + let active_interfaces: Vec = active_connections + .iter() + .map(|con| con.interface_name) + .collect(); + match IS_MACOS { + true => { + let mut counter = 3; + let mut interface_name = format!("utun{}", counter); + + while active_interfaces.contains(&interface_name) { + counter += 1; + interface_name = format!("utun{}", counter); + } + + return interface_name; + } + false => remove_whitespace(&location.name), + } +} + fn is_port_free(port: u16) -> bool { if let Ok(listener) = TcpListener::bind(format!("127.0.0.1:{}", port)) { // Port is available; close the listener @@ -170,3 +196,32 @@ where self } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::database::Location; + use chrono::Utc; + + #[test] + fn test_macos_existing_interfaces() { + let location = Location { + id: None, + instance_id: 1, + network_id: 2, + name: "Example Location".to_string(), + address: "123 Main St".to_string(), + pubkey: "public_key_here".to_string(), + endpoint: "endpoint_here".to_string(), + allowed_ips: "allowed_ips_here".to_string(), + }; + let active_connections = vec![ActiveConnection { + location_id: 1, + start: Utc::now().naive_utc(), + connected_from: "Test".to_string(), + interface_name: "utun3".to_string(), + }]; + + assert_eq!(get_interface_name(&location, active_connections), "utun4"); + } +} From 6ea854f67bff0f30590bb1392c366d62283b8851 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 10:44:47 +0200 Subject: [PATCH 5/8] test --- src-tauri/src/commands.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 2149b75a..904c9bcb 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -102,16 +102,10 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() .map_err(|err| err.to_string()) .log()? { - let interface_name: String = state.get_connections().iter().map(|conn| con.loca) - let api = WGApi::new(remove_whitespace(&location.name), IS_MACOS) - .map_err(|e| e.to_string()) - .log()?; - debug!("Removing interface"); - api.remove_interface() - .map_err(|err| err.to_string()) - .log()?; debug!("Removed interface"); if let Some(connection) = state.find_and_remove_connection(location_id) { + let api = WGApi::new(connection.interface_name, IS_MACOS); + api.remove_interface().await?; debug!("Saving connection: {:#?}", connection); let mut connection: Connection = connection.into(); connection @@ -238,19 +232,19 @@ pub async fn all_instances(app_state: State<'_, AppState>) -> Result = vec![]; + let connection_ids: Vec = app_state + .active_connections + .lock() + .unwrap() + .iter() + .map(|connection| connection.location_id) + .collect(); for instance in &instances { debug!("Checking if instance: {:#?} is active", instance.uuid); let locations = Location::find_by_instance_id(&app_state.get_pool(), instance.id.unwrap()) .await .map_err(|err| err.to_string()) .log()?; - let connection_ids: Vec = app_state - .active_connections - .lock() - .unwrap() - .iter() - .map(|connection| connection.location_id) - .collect(); let location_ids: Vec = locations .iter() .map(|location| location.id.unwrap()) From 8acb28f3a245520771ae677cede9340764e9ef23 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 11:18:24 +0200 Subject: [PATCH 6/8] Refactoring --- src-tauri/src/commands.rs | 34 +++++++++++++++------------------- src-tauri/src/error.rs | 2 ++ src-tauri/src/utils.rs | 38 ++++---------------------------------- 3 files changed, 21 insertions(+), 53 deletions(-) diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 180e5bd9..9aaf9b43 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -4,10 +4,10 @@ use crate::{ Location, LocationStats, WireguardKeys, }, error::Error, - utils::{get_interface_name, setup_interface, spawn_stats_thread, IS_MACOS}, + utils::{create_api, get_interface_name, setup_interface, spawn_stats_thread}, AppState, }; -use defguard_wireguard_rs::{WGApi, WireguardInterfaceApi}; +use defguard_wireguard_rs::WireguardInterfaceApi; use local_ip_address::local_ip; use serde::{Deserialize, Serialize}; use tauri::{Manager, State}; @@ -36,14 +36,12 @@ pub async fn connect(location_id: i64, handle: tauri::AppHandle) -> Result<(), E state.active_connections.lock().unwrap() ); debug!("Sending event connection-changed."); - handle - .emit_all( - "connection-changed", - Payload { - message: "Created new connection".into(), - }, - ) - .unwrap(); + handle.emit_all( + "connection-changed", + Payload { + message: "Created new connection".into(), + }, + )?; // Spawn stats threads debug!("Spawning stats thread"); let _ = spawn_stats_thread(handle, location, api).await; @@ -59,21 +57,19 @@ pub async fn disconnect(location_id: i64, handle: tauri::AppHandle) -> Result<() if let Some(connection) = state.find_and_remove_connection(location_id) { debug!("Found active connection: {:#?}", connection); debug!("Creating api to remove interface"); - let api = WGApi::new(connection.interface_name.clone(), IS_MACOS)?; + let api = create_api(&connection.interface_name)?; api.remove_interface()?; debug!("Removed interface"); debug!("Saving connection: {:#?}", connection); let mut connection: Connection = connection.into(); connection.save(&state.get_pool()).await?; debug!("Saved connection: {:#?}", connection); - handle - .emit_all( - "connection-changed", - Payload { - message: "Created new connection".into(), - }, - ) - .unwrap(); + handle.emit_all( + "connection-changed", + Payload { + message: "Created new connection".into(), + }, + )?; Ok(()) } else { error!("Connection for location with id: {} not found", location_id); diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index 589ae0ab..21a8f9c3 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -30,6 +30,8 @@ pub enum Error { InternalError, #[error("Object not found")] NotFound, + #[error("Tauri error: {0}")] + Tauri(#[from] tauri::Error), } // we must manually implement serde::Serialize diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 71685c8d..2f602ee5 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -27,12 +27,11 @@ pub async fn setup_interface( ) -> Result { if let Some(keys) = WireguardKeys::find_by_instance_id(pool, location.instance_id).await? { debug!("Creating api for interface: '{}'", interface_name); - let api = create_api(&interface_name)?; + let api = create_api(interface_name)?; api.create_interface()?; - // TODO: handle unwrap debug!("Decoding location public key: {}.", location.pubkey); - let peer_key: Key = Key::from_str(&location.pubkey).unwrap(); + let peer_key: Key = Key::from_str(&location.pubkey)?; let mut peer = Peer::new(peer_key); debug!("Parsing location endpoint: {}", location.endpoint); let endpoint: SocketAddr = location.endpoint.parse()?; @@ -52,7 +51,7 @@ pub async fn setup_interface( peer.allowed_ips.push(addr); // TODO: Handle windows when wireguard_rs adds support // Add a route for the allowed IP using the `ip -4 route add` command - if let Err(err) = add_route(&allowed_ip, &interface_name) { + if let Err(err) = add_route(&allowed_ip, interface_name) { error!("Error adding route for {}: {}", allowed_ip, err); } else { debug!("Added route for {}", allowed_ip); @@ -158,7 +157,7 @@ pub fn get_interface_name( interface_name = format!("utun{}", counter); } - return interface_name; + interface_name } false => remove_whitespace(&location.name), } @@ -179,35 +178,6 @@ pub fn create_api(interface_name: &str) -> Result { Ok(WGApi::new(interface_name.to_string(), IS_MACOS)?) } -#[cfg(test)] -mod tests { - use super::*; - use crate::database::Location; - use chrono::Utc; - - #[test] - fn test_macos_existing_interfaces() { - let location = Location { - id: None, - instance_id: 1, - network_id: 2, - name: "Example Location".to_string(), - address: "123 Main St".to_string(), - pubkey: "public_key_here".to_string(), - endpoint: "endpoint_here".to_string(), - allowed_ips: "allowed_ips_here".to_string(), - }; - let active_connections = vec![ActiveConnection { - location_id: 1, - start: Utc::now().naive_utc(), - connected_from: "Test".to_string(), - interface_name: "utun3".to_string(), - }]; - - assert_eq!(get_interface_name(&location, active_connections), "utun4"); - } -} - pub async fn spawn_stats_thread( handle: tauri::AppHandle, location: Location, From 9165d89a1b8288fbeb1980d67710c51de8f4df81 Mon Sep 17 00:00:00 2001 From: akantorczyk Date: Fri, 6 Oct 2023 11:19:53 +0200 Subject: [PATCH 7/8] fix comment --- src-tauri/src/database/models/connection.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/database/models/connection.rs b/src-tauri/src/database/models/connection.rs index ece7b117..1b71de95 100644 --- a/src-tauri/src/database/models/connection.rs +++ b/src-tauri/src/database/models/connection.rs @@ -111,6 +111,7 @@ impl ConnectionInfo { } } +/// Connections stored in memory after creating interface #[derive(Debug, Serialize, Clone)] pub struct ActiveConnection { pub location_id: i64, @@ -120,7 +121,7 @@ pub struct ActiveConnection { } impl ActiveConnection { pub fn new(location_id: i64, connected_from: String, interface_name: String) -> Self { - let start = Utc::now().naive_utc(); // Get the current time as NaiveDateTime in UTC + let start = Utc::now().naive_utc(); Self { location_id, connected_from, @@ -133,7 +134,7 @@ impl ActiveConnection { impl From for Connection { fn from(active_connection: ActiveConnection) -> Self { Connection { - id: None, // Assuming you want to set it to None for new conversions + id: None, location_id: active_connection.location_id, connected_from: active_connection.connected_from, start: active_connection.start, From 8390260a11e6d4eb514f60ee4fe93eff774a31a8 Mon Sep 17 00:00:00 2001 From: dzania Date: Mon, 9 Oct 2023 11:31:14 +0200 Subject: [PATCH 8/8] Fix const --- src-tauri/src/utils.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 2f602ee5..babfe813 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -18,6 +18,7 @@ use tauri::Manager; use tokio::time::{sleep, Duration}; pub static IS_MACOS: bool = cfg!(target_os = "macos"); +pub static STATS_PERIOD: u64 = 60; /// Setup client interface pub async fn setup_interface( @@ -212,7 +213,7 @@ pub async fn spawn_stats_thread( break; } } - sleep(Duration::from_secs(60)).await; + sleep(Duration::from_secs(STATS_PERIOD)).await; } }); }