diff --git a/apps/desktop/src-tauri/src/agent.rs b/apps/desktop/src-tauri/src/agent.rs index e18b530..3066157 100644 --- a/apps/desktop/src-tauri/src/agent.rs +++ b/apps/desktop/src-tauri/src/agent.rs @@ -792,6 +792,106 @@ fn collect_windows_extended() -> serde_json::Value { ps("@(Get-Service | Select-Object Name,Status,DisplayName)").unwrap_or_else(|| json!([])); let defender = ps("Get-MpComputerStatus | Select-Object AMRunningMode,AntivirusEnabled,RealTimeProtectionEnabled,AntispywareEnabled").unwrap_or_else(|| json!({})); let hotfix = ps("Get-HotFix | Select-Object HotFixID,InstalledOn").unwrap_or_else(|| json!([])); + let bitlocker = ps( + "@(if (Get-Command -Name Get-BitLockerVolume -ErrorAction SilentlyContinue) { Get-BitLockerVolume | Select-Object MountPoint,VolumeStatus,ProtectionStatus,LockStatus,EncryptionMethod,EncryptionPercentage,CapacityGB,KeyProtector } else { @() })", + ) + .unwrap_or_else(|| json!([])); + let tpm = ps( + "if (Get-Command -Name Get-Tpm -ErrorAction SilentlyContinue) { Get-Tpm | Select-Object TpmPresent,TpmReady,TpmEnabled,TpmActivated,ManagedAuthLevel,OwnerAuth,ManufacturerId,ManufacturerIdTxt,ManufacturerVersion,ManufacturerVersionFull20,SpecVersion } else { $null }", + ) + .unwrap_or_else(|| json!({})); + let secure_boot = ps( + r#" + if (-not (Get-Command -Name Confirm-SecureBootUEFI -ErrorAction SilentlyContinue)) { + [PSCustomObject]@{ Supported = $false; Enabled = $null; Error = 'Cmdlet Confirm-SecureBootUEFI indisponível' } + } else { + try { + $enabled = Confirm-SecureBootUEFI + [PSCustomObject]@{ Supported = $true; Enabled = [bool]$enabled; Error = $null } + } catch { + [PSCustomObject]@{ Supported = $true; Enabled = $null; Error = $_.Exception.Message } + } + } + "#, + ) + .unwrap_or_else(|| json!({})); + let device_guard = ps( + "@(Get-CimInstance -ClassName Win32_DeviceGuard | Select-Object SecurityServicesConfigured,SecurityServicesRunning,RequiredSecurityProperties,AvailableSecurityProperties,VirtualizationBasedSecurityStatus)", + ) + .unwrap_or_else(|| json!([])); + let firewall_profiles = ps( + "@(Get-NetFirewallProfile | Select-Object Name,Enabled,DefaultInboundAction,DefaultOutboundAction,NotifyOnListen)", + ) + .unwrap_or_else(|| json!([])); + let windows_update = ps( + r#" + $reg = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' -ErrorAction SilentlyContinue + if ($null -eq $reg) { return $null } + $last = $null + if ($reg.PSObject.Properties.Name -contains 'LastSuccessTime') { + $raw = $reg.LastSuccessTime + if ($raw) { + try { + if ($raw -is [DateTime]) { + $last = ($raw.ToUniversalTime()).ToString('o') + } elseif ($raw -is [string]) { + $last = $raw + } else { + $last = [DateTime]::FromFileTimeUtc([long]$raw).ToString('o') + } + } catch { + $last = $raw + } + } + } + [PSCustomObject]@{ + AUOptions = $reg.AUOptions + NoAutoUpdate = $reg.NoAutoUpdate + ScheduledInstallDay = $reg.ScheduledInstallDay + ScheduledInstallTime = $reg.ScheduledInstallTime + DetectionFrequency = $reg.DetectionFrequencyEnabled + LastSuccessTime = $last + } + "#, + ) + .unwrap_or_else(|| json!({})); + let computer_system = ps( + "Get-CimInstance Win32_ComputerSystem | Select-Object Manufacturer,Model,Domain,DomainRole,PartOfDomain,Workgroup,TotalPhysicalMemory,HypervisorPresent,PCSystemType,PCSystemTypeEx", + ) + .unwrap_or_else(|| json!({})); + let device_join = ps( + r#" + $output = & dsregcmd.exe /status 2>$null + if (-not $output) { return $null } + $map = [ordered]@{} + $current = $null + foreach ($line in $output) { + if ([string]::IsNullOrWhiteSpace($line)) { continue } + if ($line -match '^\[(.+)\]$') { + $current = $matches[1].Trim() + if (-not $map.Contains($current)) { + $map[$current] = [ordered]@{} + } + continue + } + if (-not $current) { continue } + $parts = $line.Split(':', 2) + if ($parts.Length -ne 2) { continue } + $key = $parts[0].Trim() + $value = $parts[1].Trim() + if ($key) { + ($map[$current])[$key] = $value + } + } + if ($map.Count -eq 0) { return $null } + $obj = [ordered]@{} + foreach ($entry in $map.GetEnumerator()) { + $obj[$entry.Key] = [PSCustomObject]$entry.Value + } + [PSCustomObject]$obj + "#, + ) + .unwrap_or_else(|| json!({})); // Informações de build/edição e ativação let os_info = ps(r#" @@ -847,6 +947,14 @@ fn collect_windows_extended() -> serde_json::Value { "memoryModules": memory, "videoControllers": video, "disks": disks, + "bitLocker": bitlocker, + "tpm": tpm, + "secureBoot": secure_boot, + "deviceGuard": device_guard, + "firewallProfiles": firewall_profiles, + "windowsUpdate": windows_update, + "computerSystem": computer_system, + "azureAdStatus": device_join, } }) } diff --git a/src/components/admin/machines/admin-machines-overview.tsx b/src/components/admin/machines/admin-machines-overview.tsx index 391cdac..06c69f4 100644 --- a/src/components/admin/machines/admin-machines-overview.tsx +++ b/src/components/admin/machines/admin-machines-overview.tsx @@ -6,7 +6,31 @@ import { useQuery } from "convex/react" import { format, formatDistanceToNowStrict } from "date-fns" import { ptBR } from "date-fns/locale" import { toast } from "sonner" -import { ClipboardCopy, ServerCog, Cpu, MemoryStick, Monitor, HardDrive, Pencil, ShieldCheck, ShieldAlert, Apple, Terminal, Power, PlayCircle, Download } from "lucide-react" +import { + ClipboardCopy, + ServerCog, + Cpu, + MemoryStick, + Monitor, + HardDrive, + Pencil, + ShieldCheck, + ShieldAlert, + Shield, + ShieldOff, + ShieldQuestion, + Lock, + Cloud, + RefreshCcw, + AlertTriangle, + Key, + Globe, + Apple, + Terminal, + Power, + PlayCircle, + Download, +} from "lucide-react" import { api } from "@/convex/_generated/api" import { Badge } from "@/components/ui/badge" @@ -147,6 +171,14 @@ type WindowsExtended = { videoControllers?: WindowsVideoController[] disks?: WindowsDiskEntry[] osInfo?: WindowsOsInfo + bitLocker?: Array> | Record + tpm?: Record + secureBoot?: Record + deviceGuard?: Array> | Record + firewallProfiles?: Array> | Record + windowsUpdate?: Record + computerSystem?: Record + azureAdStatus?: Record } type MacExtended = { @@ -742,10 +774,126 @@ function formatPercent(value?: number | null) { return `${normalized.toFixed(0)}%` } -function readBool(source: unknown, key: string): boolean | undefined { - if (!source || typeof source !== "object") return undefined - const value = (source as Record)[key] - return typeof value === "boolean" ? value : undefined +const BADGE_POSITIVE = "gap-1 border-emerald-500/20 bg-emerald-500/15 text-emerald-700" +const BADGE_WARNING = "gap-1 border-amber-500/20 bg-amber-100 text-amber-700" +const BADGE_NEUTRAL = "gap-1 border-slate-300 bg-slate-100 text-slate-600" + +function parseBooleanLike(value: unknown): boolean | undefined { + if (typeof value === "boolean") return value + if (typeof value === "number") { + if (value === 1) return true + if (value === 0) return false + } + if (typeof value === "string") { + const normalized = value.trim().toLowerCase() + if (["yes", "sim", "true", "enabled", "on", "ativo", "active", "y", "1"].includes(normalized)) return true + if (["no", "não", "nao", "false", "disabled", "off", "inativo", "not joined", "n", "0"].includes(normalized)) return false + } + return undefined +} + +function toNumberArray(value: unknown): number[] { + if (!value) return [] + if (Array.isArray(value)) { + return value + .map((item) => { + if (typeof item === "number") return item + if (typeof item === "string") { + const parsed = Number(item) + return Number.isNaN(parsed) ? null : parsed + } + return null + }) + .filter((item): item is number => item !== null) + } + if (typeof value === "number") return [value] + if (typeof value === "string" && value.trim().length > 0) { + return value + .replace(/[^\d,]/g, " ") + .split(/[,\s]+/) + .map((part) => Number(part)) + .filter((num) => !Number.isNaN(num)) + } + return [] +} + +function describeDomainRole(role?: number | null): string | null { + if (role === null || role === undefined) return null + const map: Record = { + 0: "Estação isolada", + 1: "Estação em domínio", + 2: "Servidor isolado", + 3: "Servidor em domínio", + 4: "Controlador de domínio (backup)", + 5: "Controlador de domínio (primário)", + } + return map[role] ?? `Função ${role}` +} + +function describePcSystemType(code?: number | null): string | null { + if (code === null || code === undefined) return null + const map: Record = { + 0: "Não especificado", + 1: "Desktop", + 2: "Portátil / Laptop", + 3: "Workstation", + 4: "Servidor corporativo", + 5: "Servidor SOHO", + 8: "Tablet / Slate", + 9: "Conversível", + 10: "Sistema baseado em detecção", + } + return map[code] ?? `Tipo ${code}` +} + +function describeDeviceGuardService(code: number): string { + const map: Record = { + 1: "Credential Guard", + 2: "HVCI (Kernel Integrity)", + 3: "Secure Boot com DMA", + 4: "Hypervisor com Device Guard", + 5: "Aplicação protegida", + } + return map[code] ?? `Serviço ${code}` +} + +function describeVbsStatus(code?: number | null): string | null { + switch (code) { + case 0: + return "VBS desabilitado" + case 1: + return "VBS habilitado (inativo)" + case 2: + return "VBS ativo (sem serviços)" + case 3: + return "VBS ativo com proteções" + default: + return code != null ? `VBS status ${code}` : null + } +} + +function describeAuOption(value?: number | null): string | null { + switch (value ?? -1) { + case 1: + return "Não configurado" + case 2: + return "Notificar antes de baixar" + case 3: + return "Baixar automático e notificar" + case 4: + return "Baixar e instalar automaticamente" + case 5: + return "Administrador local define" + default: + return value != null ? `Opção ${value}` : null + } +} + +function describeScheduledDay(value?: number | null): string | null { + if (value === null || value === undefined) return null + if (value === 0) return "Todos os dias" + const map = ["Domingo", "Segunda", "Terça", "Quarta", "Quinta", "Sexta", "Sábado"] + return map[value - 1] ?? `Dia ${value}` } function getStatusVariant(status?: string | null) { @@ -1092,6 +1240,217 @@ export function MachineDetails({ machine }: MachineDetailsProps) { return null } })() + const windowsBitLockerRaw = windowsExt?.bitLocker ?? windowsExt?.bitlocker ?? null + const windowsBitLockerVolumes = useMemo(() => { + if (Array.isArray(windowsBitLockerRaw)) return windowsBitLockerRaw + if (windowsBitLockerRaw && typeof windowsBitLockerRaw === "object") return [windowsBitLockerRaw] + return [] + }, [windowsBitLockerRaw]) + const windowsBitLockerSummary = useMemo(() => { + if (windowsBitLockerVolumes.length === 0) return null + let protectedCount = 0 + let lockedCount = 0 + windowsBitLockerVolumes.forEach((volume) => { + const record = toRecord(volume) ?? {} + const protection = readString(record, "ProtectionStatus", "protectionStatus")?.toLowerCase() + if (protection && (protection.includes("on") || protection.includes("ativo"))) { + protectedCount += 1 + } + const lockStatus = readString(record, "LockStatus", "lockStatus")?.toLowerCase() + if (lockStatus && (lockStatus.includes("locked") || lockStatus.includes("bloqueado"))) { + lockedCount += 1 + } + }) + return { total: windowsBitLockerVolumes.length, protectedCount, lockedCount } + }, [windowsBitLockerVolumes]) + const windowsTpm = toRecord(windowsExt?.tpm ?? (windowsExt as Record | undefined)?.["TPM"]) + const windowsSecureBoot = toRecord(windowsExt?.secureBoot ?? (windowsExt as Record | undefined)?.["secureboot"]) + const windowsDeviceGuardRaw = windowsExt?.deviceGuard ?? (windowsExt as Record | undefined)?.["deviceguard"] ?? null + const windowsDeviceGuard = useMemo(() => { + if (Array.isArray(windowsDeviceGuardRaw)) return windowsDeviceGuardRaw + if (windowsDeviceGuardRaw && typeof windowsDeviceGuardRaw === "object") return [windowsDeviceGuardRaw] + return [] + }, [windowsDeviceGuardRaw]) + const windowsDeviceGuardDetails = useMemo(() => { + if (!windowsDeviceGuard.length) return null + const primary = toRecord(windowsDeviceGuard[0]) ?? {} + const configured = toNumberArray(primary?.["SecurityServicesConfigured"]) + const running = toNumberArray(primary?.["SecurityServicesRunning"]) + const required = toNumberArray(primary?.["RequiredSecurityProperties"]) + const available = toNumberArray(primary?.["AvailableSecurityProperties"]) + const vbsRaw = primary?.["VirtualizationBasedSecurityStatus"] + const vbs = + typeof vbsRaw === "number" + ? vbsRaw + : typeof vbsRaw === "string" && vbsRaw.trim().length > 0 + ? Number(vbsRaw) + : undefined + return { primary, configured, running, required, available, vbs } + }, [windowsDeviceGuard]) + const deviceGuardConfiguredLabels = windowsDeviceGuardDetails?.configured?.map((code) => describeDeviceGuardService(code)) ?? [] + const deviceGuardRunningLabels = windowsDeviceGuardDetails?.running?.map((code) => describeDeviceGuardService(code)) ?? [] + const windowsFirewallProfilesRaw = + windowsExt?.firewallProfiles ?? (windowsExt as Record | undefined)?.["firewallprofiles"] ?? null + const windowsFirewallProfiles = useMemo(() => { + if (Array.isArray(windowsFirewallProfilesRaw)) return windowsFirewallProfilesRaw + if (windowsFirewallProfilesRaw && typeof windowsFirewallProfilesRaw === "object") return [windowsFirewallProfilesRaw] + return [] + }, [windowsFirewallProfilesRaw]) + const windowsUpdateSettings = toRecord(windowsExt?.windowsUpdate ?? (windowsExt as Record | undefined)?.["windowsupdate"]) + const windowsUpdateLastSuccess = useMemo(() => { + if (!windowsUpdateSettings) return null + const candidates = [ + windowsUpdateSettings["LastSuccessTime"], + windowsUpdateSettings["lastSuccessTime"], + windowsUpdateSettings["LastSuccessTimeUtc"], + windowsUpdateSettings["lastSuccessTimeUtc"], + ] + for (const candidate of candidates) { + const parsed = parseDateish(candidate) + if (parsed) return parsed + if (typeof candidate === "string" && candidate.trim().length > 0) { + const parsedIso = new Date(candidate) + if (!Number.isNaN(parsedIso.getTime())) return parsedIso + } + } + return null + }, [windowsUpdateSettings]) + const windowsUpdateLastSuccessLabel = windowsUpdateLastSuccess ? formatAbsoluteDateTime(windowsUpdateLastSuccess) : null + const windowsComputerSystem = toRecord( + windowsExt?.computerSystem ?? (windowsExt as Record | undefined)?.["computersystem"] + ) + const windowsAzureAdStatusRaw = toRecord( + windowsExt?.azureAdStatus ?? (windowsExt as Record | undefined)?.["azureadstatus"] + ) + const windowsAzureAdStatus = useMemo(() => { + if (!windowsAzureAdStatusRaw) return null + return Object.entries(windowsAzureAdStatusRaw).reduce>>((acc, [section, value]) => { + acc[section] = toRecord(value) ?? {} + return acc + }, {}) + }, [windowsAzureAdStatusRaw]) + const secureBootSupported = windowsSecureBoot + ? parseBooleanLike(windowsSecureBoot["Supported"] ?? windowsSecureBoot["supported"]) + : undefined + const secureBootEnabled = windowsSecureBoot + ? parseBooleanLike(windowsSecureBoot["Enabled"] ?? windowsSecureBoot["enabled"]) + : undefined + const secureBootError = windowsSecureBoot ? readString(windowsSecureBoot, "Error", "error") : undefined + const tpmPresent = windowsTpm ? parseBooleanLike(windowsTpm["TpmPresent"] ?? windowsTpm["tpmPresent"]) : undefined + const tpmReady = windowsTpm ? parseBooleanLike(windowsTpm["TpmReady"] ?? windowsTpm["tpmReady"]) : undefined + const tpmEnabled = windowsTpm ? parseBooleanLike(windowsTpm["TpmEnabled"] ?? windowsTpm["tpmEnabled"]) : undefined + const tpmActivated = windowsTpm ? parseBooleanLike(windowsTpm["TpmActivated"] ?? windowsTpm["tpmActivated"]) : undefined + const tpmManufacturer = + windowsTpm ? readString(windowsTpm, "ManufacturerIdTxt", "manufacturerIdTxt", "ManufacturerId", "manufacturerId") : undefined + const tpmVersion = + windowsTpm + ? readString(windowsTpm, "ManufacturerVersionFull20", "manufacturerVersionFull20", "ManufacturerVersion", "manufacturerVersion", "SpecVersion") + : undefined + const windowsFirewallNormalized = useMemo(() => { + return windowsFirewallProfiles.map((profile) => { + const record = toRecord(profile) ?? {} + return { + name: readString(record, "Name", "name") ?? "Perfil", + enabled: parseBooleanLike(record["Enabled"] ?? record["enabled"]), + inboundAction: readString(record, "DefaultInboundAction", "defaultInboundAction"), + outboundAction: readString(record, "DefaultOutboundAction", "defaultOutboundAction"), + notifyOnListen: parseBooleanLike(record["NotifyOnListen"] ?? record["notifyOnListen"]), + } + }) + }, [windowsFirewallProfiles]) + const firewallEnabledCount = windowsFirewallNormalized.filter((profile) => profile.enabled !== false).length + const windowsUpdateMode = windowsUpdateSettings ? describeAuOption(readNumber(windowsUpdateSettings, "AUOptions", "auOptions")) : null + const windowsUpdateDay = windowsUpdateSettings + ? describeScheduledDay(readNumber(windowsUpdateSettings, "ScheduledInstallDay", "scheduledInstallDay")) + : null + const windowsUpdateHourRaw = windowsUpdateSettings + ? readNumber(windowsUpdateSettings, "ScheduledInstallTime", "scheduledInstallTime") + : undefined + const windowsUpdateHour = + windowsUpdateHourRaw != null ? `${windowsUpdateHourRaw.toString().padStart(2, "0")}h` : null + const windowsUpdateDisabled = windowsUpdateSettings + ? parseBooleanLike(windowsUpdateSettings["NoAutoUpdate"] ?? windowsUpdateSettings["noAutoUpdate"]) + : undefined + const windowsUpdateDetectionEnabled = windowsUpdateSettings + ? parseBooleanLike( + windowsUpdateSettings["DetectionFrequency"] ?? + windowsUpdateSettings["DetectionFrequencyEnabled"] ?? + windowsUpdateSettings["detectionFrequencyEnabled"], + ) + : undefined + const windowsUpdateScheduleLabel = + windowsUpdateDay || windowsUpdateHour + ? `${windowsUpdateDay ?? ""}${windowsUpdateDay && windowsUpdateHour ? ` · ${windowsUpdateHour}` : windowsUpdateHour ?? ""}`.trim() + : null + const computerDomain = windowsComputerSystem ? readString(windowsComputerSystem, "Domain", "domain") : undefined + const computerWorkgroup = windowsComputerSystem ? readString(windowsComputerSystem, "Workgroup", "workgroup") : undefined + const computerPartOfDomain = windowsComputerSystem + ? parseBooleanLike(windowsComputerSystem["PartOfDomain"] ?? windowsComputerSystem["partOfDomain"]) + : undefined + const computerDomainRole = windowsComputerSystem + ? readNumber(windowsComputerSystem, "DomainRole", "domainRole") + : undefined + const computerManufacturer = windowsComputerSystem + ? readString(windowsComputerSystem, "Manufacturer", "manufacturer") + : undefined + const computerModel = windowsComputerSystem ? readString(windowsComputerSystem, "Model", "model") : undefined + const computerPcType = windowsComputerSystem + ? readNumber(windowsComputerSystem, "PCSystemType", "pcSystemType", "PCSystemTypeEx", "pcSystemTypeEx") + : undefined + const computerTotalMemory = windowsComputerSystem + ? readNumber(windowsComputerSystem, "TotalPhysicalMemory", "totalPhysicalMemory") + : undefined + const computerDomainRoleLabel = describeDomainRole(computerDomainRole) + const computerPcTypeLabel = describePcSystemType(computerPcType) + const computerTotalMemoryLabel = typeof computerTotalMemory === "number" ? formatBytes(computerTotalMemory) : null + const azureDeviceState = windowsAzureAdStatus ? windowsAzureAdStatus["Device State"] ?? null : null + const azureTenantDetails = windowsAzureAdStatus ? windowsAzureAdStatus["Tenant Details"] ?? null : null + const azureUserState = windowsAzureAdStatus ? windowsAzureAdStatus["User State"] ?? null : null + const azureAdJoined = azureDeviceState ? parseBooleanLike(azureDeviceState["AzureAdJoined"]) : undefined + const azureDomainJoined = azureDeviceState ? parseBooleanLike(azureDeviceState["DomainJoined"]) : undefined + const azureEnterpriseJoined = azureDeviceState ? parseBooleanLike(azureDeviceState["EnterpriseJoined"]) : undefined + const azureTenantName = + (azureDeviceState ? readString(azureDeviceState, "TenantName") : undefined) ?? + (azureTenantDetails ? readString(azureTenantDetails, "TenantName") : undefined) + const azureDeviceId = + (azureDeviceState ? readString(azureDeviceState, "DeviceId") : undefined) ?? + (azureTenantDetails ? readString(azureTenantDetails, "DeviceId") : undefined) + const azureUserSso = azureUserState + ? readString(azureUserState, "AzureAdPrt") ?? + (azureUserState["AzureAdPrt"] ? String(azureUserState["AzureAdPrt"]) : undefined) + : undefined + const defenderAntivirus = windowsExt.defender + ? parseBooleanLike(windowsExt.defender["AntivirusEnabled"] ?? windowsExt.defender["antivirusEnabled"]) + : undefined + const defenderRealtime = windowsExt.defender + ? parseBooleanLike( + windowsExt.defender["RealTimeProtectionEnabled"] ?? windowsExt.defender["realTimeProtectionEnabled"], + ) + : undefined + const defenderMode = windowsExt.defender ? readString(windowsExt.defender, "AMRunningMode", "amRunningMode") : undefined + const windowsHotfixes = useMemo(() => { + if (!Array.isArray(windowsExt?.hotfix)) return [] + return windowsExt.hotfix + .map((entry) => { + const record = toRecord(entry) ?? {} + const id = + readString(record, "HotFixID", "hotFixId", "HotfixId", "Id", "id") ?? + "Atualização" + const installedAt = parseDateish(record["InstalledOn"] ?? record["installedOn"]) + const installedLabel = installedAt + ? formatAbsoluteDateTime(installedAt) + : readString(record, "InstalledOn", "installedOn") ?? "—" + return { id, installedAt, installedLabel } + }) + .sort((a, b) => { + if (a.installedAt && b.installedAt) { + return b.installedAt.getTime() - a.installedAt.getTime() + } + if (a.installedAt) return -1 + if (b.installedAt) return 1 + return a.id.localeCompare(b.id) + }) + }, [windowsExt?.hotfix]) const osNameDisplay = useMemo(() => { const base = machine?.osName?.trim() const edition = windowsEditionLabel?.trim() @@ -1806,7 +2165,7 @@ export function MachineDetails({ machine }: MachineDetailsProps) { {/* Windows */} {windowsExt ? ( -
+
{/* Cards resumidos: CPU / RAM / GPU / Discos */}
@@ -1862,28 +2221,371 @@ export function MachineDetails({ machine }: MachineDetailsProps) {
- {windowsOsInfo ? ( -
-

Informações do Windows

-
- - - - - - - - - - - - -
-
- ) : null} +
+ + + + + Sistema operacional + + Build, licença e data de instalação + + +
+ {windowsVersionLabel ? ( + + + {windowsVersionLabel} + + ) : null} + {windowsBuildLabel ? ( + Build {windowsBuildLabel} + ) : null} + {windowsLicenseStatusLabel ? ( + + {windowsActivationStatus ? : } + {windowsLicenseStatusLabel} + + ) : null} +
+
+ + + + + + + + +
+
+
+ + + + + + Identidade e dispositivo + + Associação a domínio, Azure AD e detalhes físicos + + +
+ + + + + + + +
+
+ {computerPartOfDomain !== undefined ? ( + + {computerPartOfDomain ? : } + {computerPartOfDomain ? `Domínio ativo${computerDomain ? ` (${computerDomain})` : ""}` : "Fora de domínio"} + + ) : null} + {azureAdJoined !== undefined ? ( + + + {azureAdJoined ? "Azure AD conectado" : "Azure AD não conectado"} + + ) : null} + {azureDomainJoined !== undefined ? ( + + + Domínio local: {azureDomainJoined ? "Sim" : "Não"} + + ) : null} + {azureEnterpriseJoined !== undefined ? ( + + + Enterprise: {azureEnterpriseJoined ? "Sim" : "Não"} + + ) : null} +
+ {azureTenantName ? ( +

Tenant: {azureTenantName}

+ ) : null} + {azureDeviceId ? ( +

Device ID: {azureDeviceId}

+ ) : null} + {azureUserSso ? ( +

Usuário SSO: {azureUserSso}

+ ) : null} +
+
+ + + + + + Atualizações do Windows + + Configurações automáticas e histórico recente + + +
+ {windowsUpdateDisabled !== undefined ? ( + + {windowsUpdateDisabled ? : } + {windowsUpdateDisabled ? "Atualizações desativadas" : "Atualizações automáticas"} + + ) : null} + {windowsUpdateDetectionEnabled === false ? ( + + + Sem detecção automática + + ) : null} +
+
+ + + +
+ {windowsHotfixes.length > 0 ? ( +
+ +

Atualizações recentes

+
    + {windowsHotfixes.slice(0, 3).map((fix) => ( +
  • + {fix.id} + {fix.installedLabel} +
  • + ))} +
+
+ ) : null} +
+
+ + + + + + Segurança do dispositivo + + Proteções do Windows, criptografia e firewall + + +
+ {windowsActivationStatus !== null && windowsActivationStatus !== undefined ? ( + + {windowsActivationStatus ? : } + {windowsActivationStatus ? "Licença ativada" : "Licença pendente"} + + ) : null} + {defenderAntivirus !== undefined ? ( + + {defenderAntivirus ? : } + Antivírus {defenderAntivirus ? "ativo" : "inativo"} + + ) : null} + {defenderRealtime !== undefined ? ( + + {defenderRealtime ? : } + Tempo real {defenderRealtime ? "ativo" : "inativo"} + + ) : null} + {secureBootSupported !== undefined ? ( + + {secureBootEnabled + ? + : secureBootSupported + ? + : } + {secureBootSupported + ? secureBootEnabled === true + ? "Secure Boot ativo" + : "Secure Boot desabilitado" + : "Secure Boot não suportado"} + + ) : null} + {windowsBitLockerSummary ? ( + + + {windowsBitLockerSummary.protectedCount}/{windowsBitLockerSummary.total} BitLocker + + ) : null} + {tpmPresent !== undefined ? ( + + + {tpmPresent ? (tpmReady ? "TPM pronto" : "TPM detectado") : "TPM ausente"} + + ) : null} + {windowsDeviceGuardDetails ? ( + + + {describeVbsStatus(windowsDeviceGuardDetails.vbs) ?? "VBS desconhecido"} + + ) : null} + {windowsFirewallNormalized.length > 0 ? ( + + + Firewall {firewallEnabledCount}/{windowsFirewallNormalized.length} + + ) : null} +
+ + {windowsExt.defender ? ( +
+

Defender

+
+ Modo: {defenderMode ?? "—"} + + Antivírus: {defenderAntivirus === undefined ? "—" : defenderAntivirus ? "Ativo" : "Inativo"} + + + Tempo real: {defenderRealtime === undefined ? "—" : defenderRealtime ? "Ativo" : "Inativo"} + +
+
+ ) : null} + + {secureBootError ? ( +
+ + {secureBootError} +
+ ) : null} + + {windowsBitLockerVolumes.length > 0 ? ( +
+
+

BitLocker

+ + {windowsBitLockerSummary + ? `${windowsBitLockerSummary.protectedCount}/${windowsBitLockerSummary.total} protegidos` + : `${windowsBitLockerVolumes.length} volumes`} + +
+
+ + + + Volume + Proteção + Bloqueio + Método + % Cript. + + + + {windowsBitLockerVolumes.map((volume, idx) => { + const record = toRecord(volume) ?? {} + const mount = readString(record, "MountPoint", "mountPoint") ?? "—" + const protection = readString(record, "ProtectionStatus", "protectionStatus") ?? "—" + const lock = readString(record, "LockStatus", "lockStatus") ?? "—" + const method = readString(record, "EncryptionMethod", "encryptionMethod") ?? "—" + const percent = readNumber(record, "EncryptionPercentage", "encryptionPercentage") + return ( + + {mount} + {protection} + {lock} + {method} + + {percent != null ? formatPercent(percent) : "—"} + + + ) + })} + +
+
+
+ ) : null} + + {windowsTpm ? ( +
+

TPM

+ Fabricante: {tpmManufacturer ?? "—"} + Versão: {tpmVersion ?? "—"} + + Status:{" "} + {tpmPresent === undefined + ? "—" + : [ + tpmPresent ? "Presente" : "Ausente", + tpmEnabled ? "Habilitado" : "Desabilitado", + tpmReady ? "Pronto" : "Não pronto", + tpmActivated ? "Ativado" : "Inativo", + ].join(" · ")} + +
+ ) : null} + + {windowsDeviceGuardDetails ? ( +
+

Device Guard

+ {describeVbsStatus(windowsDeviceGuardDetails.vbs) ?? "—"} + {deviceGuardConfiguredLabels.length > 0 ? ( + Configurado: {deviceGuardConfiguredLabels.join(", ")} + ) : null} + {deviceGuardRunningLabels.length > 0 ? ( + Em execução: {deviceGuardRunningLabels.join(", ")} + ) : null} +
+ ) : null} + + {windowsFirewallNormalized.length > 0 ? ( +
+
+

Perfis de firewall

+ + {firewallEnabledCount}/{windowsFirewallNormalized.length} ativos + +
+
+ + + + Perfil + Entrada + Saída + + + + {windowsFirewallNormalized.map((profile, idx) => ( + + {profile.name} + + {profile.inboundAction ?? "—"} + + + {profile.outboundAction ?? "—"} + + + ))} + +
+
+
+ ) : null} +
+
+
{windowsCpuDetails.length > 0 ? (
@@ -2120,31 +2822,6 @@ export function MachineDetails({ machine }: MachineDetailsProps) {
) : null} - {windowsExt.defender ? ( -
-

Defender

-
- {readBool(windowsExt.defender, "AntivirusEnabled") === true ? ( - - Antivírus: Ativo - - ) : ( - - Antivírus: Inativo - - )} - {readBool(windowsExt.defender, "RealTimeProtectionEnabled") === true ? ( - - Proteção em tempo real: Ativa - - ) : ( - - Proteção em tempo real: Inativa - - )} -
-
- ) : null}
) : null}