use std::env; use std::path::PathBuf; use crate::services::system; #[derive(Debug, Clone)] pub struct PermissionStatus { pub admin: bool, pub firewall_configured: bool, pub defender_exception: bool, pub network_ok: bool, pub issues: Vec, } pub struct WindowsPermissions; impl WindowsPermissions { /// Verifica se o processo está rodando com privilégios de administrador pub fn check_admin() -> bool { let ps_cmd = r#"[Security.Principal.WindowsPrincipal]::Current.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)"#; match system::run_cmd("powershell", &["-NoProfile", "-Command", ps_cmd]) { Ok(output) => { let trimmed = output.trim().to_lowercase(); trimmed == "true" } Err(_) => false, } } /// Verifica se uma regra de firewall já existe fn firewall_rule_exists(display_name: &str) -> bool { let ps_cmd = format!( r#"Get-NetFirewallRule -DisplayName '{}' -ErrorAction SilentlyContinue | Select-Object -First 1"#, display_name ); match system::run_cmd("powershell", &["-NoProfile", "-Command", &ps_cmd]) { Ok(output) => !output.trim().is_empty(), Err(_) => false, } } /// Adiciona regra no firewall do Windows para uma porta específica pub fn request_firewall_rule(port: u16, name: &str) -> Result<(), String> { let display_name = format!("OllaHubBackend {}", name); // Verificar se já existe if Self::firewall_rule_exists(&display_name) { system::info(&format!("Regra de firewall '{}' já existe", display_name)); return Ok(()); } // Verificar se tem privilégios de admin if !Self::check_admin() { return Err(format!( "Privilégios de administrador necessários para adicionar regra de firewall na porta {}. Execute como Administrador.", port )); } // Criar regra de firewall let ps_cmd = format!( r#"New-NetFirewallRule -DisplayName '{}' -Direction Inbound -LocalPort {} -Protocol TCP -Action Allow -Profile Domain,Private,Public"#, display_name, port ); match system::run_cmd("powershell", &["-NoProfile", "-Command", &ps_cmd]) { Ok(_) => { system::info(&format!("Regra de firewall criada para porta {} ({})", port, name)); Ok(()) } Err(e) => Err(format!("Falha ao criar regra de firewall: {}", e)), } } /// Obtém o caminho do executável atual fn get_executable_path() -> Result { env::current_exe().map_err(|e| format!("Não foi possível obter caminho do executável: {}", e)) } /// Verifica se exceção já existe no Windows Defender fn defender_exception_exists(path: &str) -> bool { let ps_cmd = format!( r#"Get-MpPreference | Select-Object -ExpandProperty ExclusionPath | Where-Object {{ $_ -eq '{}' }}"#, path.replace('\\', "\\\\") ); match system::run_cmd("powershell", &["-NoProfile", "-Command", &ps_cmd]) { Ok(output) => !output.trim().is_empty(), Err(_) => false, } } /// Adiciona exceção no Windows Defender para o executável pub fn request_defender_exception(exe_path: &str) -> Result<(), String> { // Verificar se já existe if Self::defender_exception_exists(exe_path) { system::info(&format!("Exceção do Windows Defender já existe para: {}", exe_path)); return Ok(()); } // Verificar se tem privilégios de admin if !Self::check_admin() { return Err(format!( "Privilégios de administrador necessários para adicionar exceção no Windows Defender. Execute como Administrador." )); } // Adicionar exceção de caminho let ps_cmd = format!( r#"Add-MpPreference -ExclusionPath '{}'"#, exe_path.replace('\'', "''") ); match system::run_cmd("powershell", &["-NoProfile", "-Command", &ps_cmd]) { Ok(_) => { system::info(&format!("Exceção do Windows Defender adicionada para: {}", exe_path)); Ok(()) } Err(e) => Err(format!("Falha ao adicionar exceção no Windows Defender: {}", e)), } } /// Verifica permissões de rede (básico) pub fn request_network_permissions() -> Result<(), String> { // Verificação básica: tentar criar um socket de teste // Se falhar, pode indicar problemas de permissão // Por enquanto, apenas retorna Ok se estiver no Windows if cfg!(target_os = "windows") { Ok(()) } else { Err("Verificação de permissões de rede apenas disponível no Windows".to_string()) } } /// Configura todas as permissões necessárias pub fn setup_all_permissions() -> Result { system::info("Verificando e configurando permissões do Windows..."); let mut status = PermissionStatus { admin: Self::check_admin(), firewall_configured: false, defender_exception: false, network_ok: false, issues: Vec::new(), }; // Log status de admin system::info("[1/4] Verificando privilégios de administrador..."); if status.admin { system::info(" ✓ Executando com privilégios de administrador"); } else { system::warn(" ⚠ Não está executando como administrador. Algumas configurações podem falhar."); status.issues.push("Execução sem privilégios de administrador".to_string()); } // Configurar firewall para porta 8080 (API) system::info("[2/4] Configurando regras de firewall..."); system::info(" → Porta 8080 (API HTTP)..."); match Self::request_firewall_rule(8080, "API") { Ok(_) => { status.firewall_configured = true; system::info(" ✓ Regra de firewall criada para porta 8080"); } Err(e) => { status.issues.push(format!("Firewall porta 8080: {}", e)); system::warn(&format!(" ✗ Falha: {}", e)); } } // Configurar firewall para porta 11434 (Ollama) system::info(" → Porta 11434 (Ollama)..."); match Self::request_firewall_rule(11434, "Ollama") { Ok(_) => { // Se a porta 8080 foi configurada, manter firewall_configured como true if !status.firewall_configured { status.firewall_configured = true; } system::info(" ✓ Regra de firewall criada para porta 11434"); } Err(e) => { status.issues.push(format!("Firewall porta 11434: {}", e)); system::warn(&format!(" ✗ Falha: {}", e)); } } // Configurar exceção no Windows Defender system::info("[3/4] Configurando exceção no Windows Defender..."); match Self::get_executable_path() { Ok(exe_path) => { let exe_str = exe_path.to_string_lossy().to_string(); system::info(&format!(" → Executável: {}", exe_str)); match Self::request_defender_exception(&exe_str) { Ok(_) => { status.defender_exception = true; system::info(" ✓ Exceção adicionada no Windows Defender"); } Err(e) => { status.issues.push(format!("Windows Defender: {}", e)); system::warn(&format!(" ✗ Falha: {}", e)); } } } Err(e) => { status.issues.push(format!("Não foi possível obter caminho do executável: {}", e)); system::warn(&format!(" ✗ Não foi possível configurar exceção no Windows Defender: {}", e)); } } // Verificar permissões de rede system::info("[4/4] Verificando permissões de rede..."); match Self::request_network_permissions() { Ok(_) => { status.network_ok = true; system::info(" ✓ Permissões de rede OK"); } Err(e) => { status.issues.push(format!("Permissões de rede: {}", e)); system::warn(&format!(" ✗ Falha: {}", e)); } } // Resumo final system::info("========================================"); if status.issues.is_empty() { system::info("✓ Todas as permissões foram configuradas com sucesso!"); } else { system::warn(&format!("⚠ {} problema(s) encontrado(s) durante configuração de permissões", status.issues.len())); system::info(""); system::info("📋 Instruções manuais para resolver problemas:"); system::info(""); if !status.admin { system::info(" 1. PRIVILÉGIOS DE ADMINISTRADOR:"); system::info(" → Clique com botão direito no executável"); system::info(" → Selecione 'Executar como administrador'"); system::info(""); } if !status.firewall_configured { system::info(" 2. REGRAS DE FIREWALL:"); system::info(" → Abra: Painel de Controle > Firewall do Windows > Configurações avançadas"); system::info(" → Clique em 'Regras de entrada' > 'Nova regra...'"); system::info(" → Tipo: Porta > TCP > Portas específicas: 8080, 11434"); system::info(" → Ação: Permitir a conexão"); system::info(" → Nome: 'OllaHubBackend API' e 'OllaHubBackend Ollama'"); system::info(""); } if !status.defender_exception { system::info(" 3. EXCEÇÃO NO WINDOWS DEFENDER:"); if let Ok(exe_path) = Self::get_executable_path() { system::info(" → Abra: Windows Security > Virus & threat protection"); system::info(" → Clique em 'Manage settings' (Gerenciar configurações)"); system::info(" → Role até 'Exclusions' > 'Add or remove exclusions'"); system::info(" → Adicione exceção de 'File' com o caminho:"); system::info(&format!(" {}", exe_path.to_string_lossy())); } system::info(""); } } system::info("========================================"); Ok(status) } }