botserver/src/basic/keywords/security_protection.rs
Rodrigo Rodriguez (Pragmatismo) 3e75bbff97 MS Office 100% Compatibility - Phase 1 Implementation
- Add rust_xlsxwriter for Excel export with formatting support
- Add docx-rs for Word document import/export with HTML conversion
- Add PPTX export support with slides, shapes, and text elements
- Refactor sheet module into 7 files (types, formulas, handlers, etc)
- Refactor docs module into 6 files (types, handlers, storage, etc)
- Refactor slides module into 6 files (types, handlers, storage, etc)
- Fix collaboration modules (borrow issues, rand compatibility)
- Add ooxmlsdk dependency for future Office 2021 features
- Fix type mismatches in slides storage
- Update security protection API router type

Features:
- Excel: Read xlsx/xlsm/xls, write xlsx with styles
- Word: Read/write docx with formatting preservation
- PowerPoint: Write pptx with slides, shapes, text
- Real-time collaboration via WebSocket (already working)
- Theme-aware UI with --sentient-* CSS variables
2026-01-11 09:56:15 -03:00

329 lines
10 KiB
Rust

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<String>,
pub running: Option<bool>,
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<i32>,
pub report_path: Option<String>,
}
pub async fn security_tool_status(
_state: Arc<AppState>,
tool_name: &str,
) -> Result<SecurityToolResult, String> {
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<AppState>,
tool_name: &str,
) -> Result<SecurityScanResult, String> {
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<AppState>,
tool_name: &str,
) -> Result<String, String> {
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<AppState>,
tool_name: &str,
) -> Result<SecurityToolResult, String> {
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<AppState>,
tool_name: &str,
) -> Result<SecurityToolResult, String> {
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<AppState>,
tool_name: &str,
) -> Result<SecurityToolResult, String> {
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<AppState>,
tool_name: &str,
) -> Result<SecurityToolResult, String> {
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<AppState>) -> Result<i32, String> {
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, String> {
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(&not_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"));
}
}