mod groups;
mod labels;
mod sources;
mod users;
use crate::cli::config::Config;
use groups::GroupTable;
use labels::LabelTable;
use malwaredb_server::State;
use sources::SourceTable;
use users::UserTable;
use std::path::PathBuf;
use std::process::ExitCode;
use std::sync::Arc;
use anyhow::Result;
use clap::{Args, ValueHint};
use eframe::egui::Color32;
const INVALID_BG: Color32 = Color32::from_rgb(255, 180, 180);
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
enum Tab {
#[default]
Users,
Groups,
Sources,
Labels,
About,
}
#[derive(Clone, Debug, Args)]
pub struct AdminGui {
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath)]
config_file: PathBuf,
}
impl AdminGui {
#[allow(clippy::unnecessary_wraps)]
pub async fn execute(self) -> Result<ExitCode> {
let state = Config::from_file(&self.config_file)?.into_state().await?;
let admin_gui_state = AdminGuiState::new(state).await?;
let options = eframe::NativeOptions {
viewport: eframe::egui::ViewportBuilder::default()
.with_inner_size([500.0, 300.0])
.with_resizable(true),
..Default::default()
};
match eframe::run_native(
"MalwareDB",
options,
Box::new(|cc| {
egui_extras::install_image_loaders(&cc.egui_ctx);
Ok(Box::new(admin_gui_state))
}),
) {
Ok(()) => Ok(ExitCode::SUCCESS),
Err(_) => Ok(ExitCode::FAILURE),
}
}
}
struct AdminGuiState {
state: Arc<State>,
active_tab: Tab,
user_table: UserTable,
group_table: GroupTable,
source_table: SourceTable,
label_table: LabelTable,
}
impl AdminGuiState {
async fn new(state: State) -> Result<Self> {
let state = Arc::new(state);
let user_table = UserTable::new(state.clone()).await?;
let group_table = GroupTable::new(state.clone()).await?;
let source_table = SourceTable::new(state.clone()).await?;
let label_table = LabelTable::new(state.clone()).await?;
Ok(Self {
active_tab: Tab::default(),
user_table,
group_table,
source_table,
label_table,
state,
})
}
}
impl eframe::App for AdminGuiState {
fn ui(&mut self, ui: &mut eframe::egui::Ui, _frame: &mut eframe::Frame) {
ui.request_repaint();
eframe::egui::Panel::top("menu").show_inside(ui, |ui| {
ui.horizontal(|ui| {
ui.selectable_value(&mut self.active_tab, Tab::Users, "Users");
ui.selectable_value(&mut self.active_tab, Tab::Groups, "Groups");
ui.selectable_value(&mut self.active_tab, Tab::Sources, "Sources");
ui.selectable_value(&mut self.active_tab, Tab::Labels, "Labels");
ui.selectable_value(&mut self.active_tab, Tab::About, "About");
});
});
eframe::egui::Panel::bottom("theme").show_inside(ui, |ui| {
eframe::egui::widgets::global_theme_preference_buttons(ui);
});
eframe::egui::CentralPanel::default().show_inside(ui, |ui| match self.active_tab {
Tab::Users => self.user_table.ui(ui),
Tab::Groups => self.group_table.ui(ui),
Tab::Sources => self.source_table.ui(ui),
Tab::Labels => self.label_table.ui(ui),
Tab::About => {
ui.add(
eframe::egui::Image::new(eframe::egui::include_image!("logo.png"))
.max_width(30.0),
);
ui.label(format!("MalwareDB {}", crate::MDB_VERSION));
ui.hyperlink_to("https://malwaredb.net", "https://malwaredb.net");
ui.hyperlink_to(
"https://github.com/malwaredb/malwaredb-rs",
"https://github.com/malwaredb/malwaredb-rs",
);
ui.separator();
#[cfg(feature = "vt")]
ui.label("VirusTotal support available.");
#[cfg(not(feature = "vt"))]
ui.label("VirusTotal support not available.");
#[cfg(feature = "yara")]
ui.label("Yara support available.");
#[cfg(not(feature = "yara"))]
ui.label("Yara support not available.");
if let Ok(server_info) = futures::executor::block_on(self.state.db_type.db_info()) {
ui.separator();
ui.label(format!("Database: {}", server_info.version));
ui.label(format!("Files: {}", server_info.num_files));
ui.label(format!("Size on disk (samples + database): {}", server_info.size));
}
}
});
}
}