use crate::security::protection::{ProtectionManager, ProtectionTool}; use crate::security::protection::manager::ProtectionConfig; use crate::shared::state::AppState; use serde::{Deserialize, Serialize}; use std::sync::Arc; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SecurityToolResult { pub tool: String, pub success: bool, pub installed: bool, pub version: Option, pub running: Option, pub message: String, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SecurityScanResult { pub tool: String, pub success: bool, pub status: String, pub findings_count: usize, pub warnings_count: usize, pub score: Option, pub report_path: Option, } pub async fn security_tool_status( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.check_tool_status(tool).await { Ok(status) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: true, installed: status.installed, version: status.version, running: status.service_running, message: if status.installed { "Tool is installed".to_string() } else { "Tool is not installed".to_string() }, }), Err(e) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: false, installed: false, version: None, running: None, message: format!("Failed to check status: {e}"), }), } } pub async fn security_run_scan( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.run_scan(tool).await { Ok(result) => Ok(SecurityScanResult { tool: tool_name.to_lowercase(), success: true, status: format!("{:?}", result.status), findings_count: result.findings.len(), warnings_count: result.warnings as usize, score: None, report_path: result.report_path, }), Err(error) => { log::error!("Security scan failed for {tool_name}: {error}"); Ok(SecurityScanResult { tool: tool_name.to_lowercase(), success: false, status: format!("error: {error}"), findings_count: 0, warnings_count: 0, score: None, report_path: None, }) } } } pub async fn security_get_report( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); manager .get_report(tool) .await .map_err(|e| format!("Failed to get report: {e}")) } pub async fn security_update_definitions( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.update_definitions(tool).await { Ok(()) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: true, installed: true, version: None, running: None, message: "Definitions updated successfully".to_string(), }), Err(e) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: false, installed: true, version: None, running: None, message: format!("Failed to update definitions: {e}"), }), } } pub async fn security_start_service( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.start_service(tool).await { Ok(()) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: true, installed: true, version: None, running: Some(true), message: "Service started successfully".to_string(), }), Err(e) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: false, installed: true, version: None, running: Some(false), message: format!("Failed to start service: {e}"), }), } } pub async fn security_stop_service( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.stop_service(tool).await { Ok(()) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: true, installed: true, version: None, running: Some(false), message: "Service stopped successfully".to_string(), }), Err(e) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: false, installed: true, version: None, running: None, message: format!("Failed to stop service: {e}"), }), } } pub async fn security_install_tool( _state: Arc, tool_name: &str, ) -> Result { let tool = parse_tool_name(tool_name)?; let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.install_tool(tool).await { Ok(()) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: true, installed: true, version: None, running: None, message: "Tool installed successfully".to_string(), }), Err(e) => Ok(SecurityToolResult { tool: tool_name.to_lowercase(), success: false, installed: false, version: None, running: None, message: format!("Failed to install tool: {e}"), }), } } pub async fn security_hardening_score(_state: Arc) -> Result { let manager = ProtectionManager::new(ProtectionConfig::default()); match manager.run_scan(ProtectionTool::Lynis).await { Ok(_result) => Ok(0), Err(e) => Err(format!("Failed to get hardening score: {e}")), } } pub fn security_tool_is_installed(status: &SecurityToolResult) -> bool { status.installed } pub fn security_service_is_running(status: &SecurityToolResult) -> bool { status.running.unwrap_or(false) } fn parse_tool_name(name: &str) -> Result { ProtectionTool::from_str(name) .ok_or_else(|| format!("Unknown security tool: {name}. Valid tools: lynis, rkhunter, chkrootkit, suricata, lmd, clamav")) } #[cfg(test)] mod tests { use super::*; #[test] fn test_parse_tool_name_valid() { assert!(parse_tool_name("lynis").is_ok()); assert!(parse_tool_name("LYNIS").is_ok()); assert!(parse_tool_name("Lynis").is_ok()); assert!(parse_tool_name("rkhunter").is_ok()); assert!(parse_tool_name("chkrootkit").is_ok()); assert!(parse_tool_name("suricata").is_ok()); assert!(parse_tool_name("lmd").is_ok()); assert!(parse_tool_name("clamav").is_ok()); } #[test] fn test_parse_tool_name_invalid() { assert!(parse_tool_name("unknown").is_err()); assert!(parse_tool_name("").is_err()); assert!(parse_tool_name("invalid_tool").is_err()); } #[test] fn test_security_tool_is_installed() { let installed = SecurityToolResult { tool: "lynis".to_string(), success: true, installed: true, version: Some("3.0.9".to_string()), running: None, message: "Tool is installed".to_string(), }; assert!(security_tool_is_installed(&installed)); let not_installed = SecurityToolResult { tool: "lynis".to_string(), success: true, installed: false, version: None, running: None, message: "Tool is not installed".to_string(), }; assert!(!security_tool_is_installed(¬_installed)); } #[test] fn test_security_service_is_running() { let running = SecurityToolResult { tool: "suricata".to_string(), success: true, installed: true, version: None, running: Some(true), message: "Service running".to_string(), }; assert!(security_service_is_running(&running)); let stopped = SecurityToolResult { tool: "suricata".to_string(), success: true, installed: true, version: None, running: Some(false), message: "Service stopped".to_string(), }; assert!(!security_service_is_running(&stopped)); let unknown = SecurityToolResult { tool: "lynis".to_string(), success: true, installed: true, version: None, running: None, message: "No service".to_string(), }; assert!(!security_service_is_running(&unknown)); } #[test] fn test_security_scan_result_serialization() { let result = SecurityScanResult { tool: "lynis".to_string(), success: true, status: "completed".to_string(), findings_count: 5, warnings_count: 12, score: Some(78), report_path: Some("/var/log/lynis-report.dat".to_string()), }; let json = serde_json::to_string(&result).expect("Failed to serialize"); assert!(json.contains("\"tool\":\"lynis\"")); assert!(json.contains("\"score\":78")); } }