UI tray app added

* Works with egui

---------

Co-authored-by: Ultradesu <ultradesu@hexor.cy>
This commit is contained in:
Alexandr Bogomyakov
2025-07-22 23:23:18 +03:00
committed by GitHub
parent af6c4d7e61
commit 99a277088a
22 changed files with 6647 additions and 88 deletions

View File

@@ -2,6 +2,7 @@ mod client;
mod db;
mod server;
mod web;
mod gui;
use clap::Parser;
use env_logger;
@@ -10,7 +11,7 @@ use log::{error, info};
/// This application manages SSH keys and flows, either as a server or client.
/// In server mode, it stores keys and flows in a PostgreSQL database.
/// In client mode, it sends keys to the server and can update the known_hosts file with keys from the server.
#[derive(Parser, Debug)]
#[derive(Parser, Debug, Clone)]
#[command(
author = env!("CARGO_PKG_AUTHORS"),
version = env!("CARGO_PKG_VERSION"),
@@ -26,21 +27,29 @@ use log::{error, info};
\n\
"
)]
struct Args {
pub struct Args {
/// Run in server mode (default: false)
#[arg(long, help = "Run in server mode")]
server: bool,
pub server: bool,
/// Run with GUI tray interface (default: false)
#[arg(long, help = "Run with GUI tray interface")]
pub gui: bool,
/// Run settings UI window (used with --gui)
#[arg(long, help = "Run settings UI window (used with --gui)")]
pub settings_ui: bool,
/// Update the known_hosts file with keys from the server after sending keys (default: false)
#[arg(
long,
help = "Server mode: Sync the known_hosts file with keys from the server"
)]
in_place: bool,
pub in_place: bool,
/// Comma-separated list of flows to manage (default: default)
#[arg(long, default_value = "default", value_parser, num_args = 1.., value_delimiter = ',', help = "Server mode: Comma-separated list of flows to manage")]
flows: Vec<String>,
pub flows: Vec<String>,
/// IP address to bind the server or client to (default: 127.0.0.1)
#[arg(
@@ -49,7 +58,7 @@ struct Args {
default_value = "127.0.0.1",
help = "Server mode: IP address to bind the server to"
)]
ip: String,
pub ip: String,
/// Port to bind the server or client to (default: 8080)
#[arg(
@@ -58,7 +67,7 @@ struct Args {
default_value = "8080",
help = "Server mode: Port to bind the server to"
)]
port: u16,
pub port: u16,
/// Hostname or IP address of the PostgreSQL database (default: 127.0.0.1)
#[arg(
@@ -66,7 +75,7 @@ struct Args {
default_value = "127.0.0.1",
help = "Server mode: Hostname or IP address of the PostgreSQL database"
)]
db_host: String,
pub db_host: String,
/// Name of the PostgreSQL database (default: khm)
#[arg(
@@ -74,7 +83,7 @@ struct Args {
default_value = "khm",
help = "Server mode: Name of the PostgreSQL database"
)]
db_name: String,
pub db_name: String,
/// Username for the PostgreSQL database (required in server mode)
#[arg(
@@ -82,7 +91,7 @@ struct Args {
required_if_eq("server", "true"),
help = "Server mode: Username for the PostgreSQL database"
)]
db_user: Option<String>,
pub db_user: Option<String>,
/// Password for the PostgreSQL database (required in server mode)
#[arg(
@@ -90,7 +99,7 @@ struct Args {
required_if_eq("server", "true"),
help = "Server mode: Password for the PostgreSQL database"
)]
db_password: Option<String>,
pub db_password: Option<String>,
/// Host address of the server to connect to in client mode (required in client mode)
#[arg(
@@ -98,7 +107,7 @@ struct Args {
required_if_eq("server", "false"),
help = "Client mode: Full host address of the server to connect to. Like https://khm.example.com"
)]
host: Option<String>,
pub host: Option<String>,
/// Flow name to use on the server
#[arg(
@@ -106,7 +115,7 @@ struct Args {
required_if_eq("server", "false"),
help = "Client mode: Flow name to use on the server"
)]
flow: Option<String>,
pub flow: Option<String>,
/// Path to the known_hosts file (default: ~/.ssh/known_hosts)
#[arg(
@@ -114,24 +123,66 @@ struct Args {
default_value = "~/.ssh/known_hosts",
help = "Client mode: Path to the known_hosts file"
)]
known_hosts: String,
pub known_hosts: String,
/// Basic auth string for client mode. Format: user:pass
#[arg(long, default_value = "", help = "Client mode: Basic Auth credentials")]
basic_auth: String,
pub basic_auth: String,
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
env_logger::init();
// Configure logging to show only khm logs, filtering out noisy library logs
env_logger::Builder::from_default_env()
.filter_level(log::LevelFilter::Warn) // Default level for all modules
.filter_module("khm", log::LevelFilter::Debug) // Our app logs
.filter_module("actix_web", log::LevelFilter::Info) // Server logs
.filter_module("reqwest", log::LevelFilter::Warn) // HTTP client
.filter_module("winit", log::LevelFilter::Error) // Window management
.filter_module("egui", log::LevelFilter::Error) // GUI framework
.filter_module("eframe", log::LevelFilter::Error) // GUI framework
.filter_module("tray_icon", log::LevelFilter::Error) // Tray icon
.filter_module("wgpu", log::LevelFilter::Error) // Graphics
.filter_module("naga", log::LevelFilter::Error) // Graphics
.filter_module("glow", log::LevelFilter::Error) // Graphics
.filter_module("tracing", log::LevelFilter::Error) // Tracing spans
.init();
info!("Starting SSH Key Manager");
let args = Args::parse();
// Check if we have the minimum required arguments
if !args.server && (args.host.is_none() || args.flow.is_none()) {
// Neither server mode nor client mode properly configured
eprintln!("Error: You must specify either server mode (--server) or client mode (--host and --flow)");
// Settings UI mode - just show settings window and exit
if args.settings_ui {
#[cfg(feature = "gui")]
{
info!("Running settings UI window");
gui::run_settings_window();
return Ok(());
}
#[cfg(not(feature = "gui"))]
{
error!("GUI features not compiled. Install system dependencies and rebuild with --features gui");
return Err(std::io::Error::new(
std::io::ErrorKind::Unsupported,
"GUI features not compiled"
));
}
}
// GUI mode has priority
if args.gui {
info!("Running in GUI mode");
if let Err(e) = gui::run_gui().await {
error!("Failed to run GUI: {}", e);
}
return Ok(());
}
// Check if we have the minimum required arguments for server/client mode
if !args.server && !args.gui && (args.host.is_none() || args.flow.is_none()) {
// Neither server mode nor client mode nor GUI mode properly configured
eprintln!("Error: You must specify either server mode (--server), client mode (--host and --flow), or GUI mode (--gui)");
eprintln!();
eprintln!("Examples:");
eprintln!(
@@ -142,6 +193,14 @@ async fn main() -> std::io::Result<()> {
" Client mode: {} --host https://khm.example.com --flow work",
env!("CARGO_PKG_NAME")
);
eprintln!(
" GUI mode: {} --gui",
env!("CARGO_PKG_NAME")
);
eprintln!(
" Settings window: {} --gui --settings-ui",
env!("CARGO_PKG_NAME")
);
eprintln!();
eprintln!("Use --help for more information.");
std::process::exit(1);