main
vue 282 lines 9.17 KB
Raw
1 <template>
2 <div class="page">
3 <div class="flex items-center justify-between">
4 <n-button text size="small" :focusable="false" @click="routeAgent().navigate()">
5 <template #icon>
6 <Icon :name="ArrowIcon" :size="16" />
7 </template>
8 Back to agents list
9 </n-button>
10 <n-button v-if="agent" text size="small" :focusable="false" @click.stop="handleDelete">
11 <template #icon>
12 <Icon :name="DeleteIcon" :size="16" />
13 </template>
14 Delete Agent
15 </n-button>
16 </div>
17
18 <CardEntity class="my-4" :highlighted="agent?.critical_asset" :loading="loadingAgent">
19 <template #headerMain>
20 <div v-if="agent" class="text-default text-xl font-bold">
21 {{ agent.hostname }}
22 </div>
23 </template>
24 <template #headerExtra>
25 <div class="flex items-center gap-2">
26 <n-tag :type="isOnline ? 'success' : 'default'" round class="rounded-lg!" :bordered="false">
27 {{ isOnline ? "ONLINE" : "OFFLINE" }}
28 </n-tag>
29
30 <n-tooltip v-if="agent">
31 <span class="text-sm">Toggle Critical Assets</span>
32 <template #trigger>
33 <n-button
34 :type="agent.critical_asset ? 'error' : 'default'"
35 ghost
36 size="small"
37 @click.stop="toggleCritical(agent.agent_id, agent.critical_asset)"
38 >
39 <template #icon>
40 <Icon :name="agent.critical_asset ? 'carbon:warning-alt' : 'carbon:checkmark'" />
41 </template>
42 {{ agent.critical_asset ? "Critical Asset" : "Non-Critical Asset" }}
43 </n-button>
44 </template>
45 </n-tooltip>
46
47 <n-tag v-if="agent?.quarantined" type="warning" round class="rounded-lg!" :bordered="false">
48 Quarantined
49 </n-tag>
50
51 <n-button size="small" :loading="upgradingAgent" @click="upgradeWazuhAgent()">
52 Upgrade Wazuh Agent
53 </n-button>
54 </div>
55 </template>
56 </CardEntity>
57
58 <n-card content-class="p-4! pt-1!">
59 <n-spin :show="loadingAgent">
60 <n-tabs type="line" animated default-value="Overview" pane-wrapper-class="min-h-100">
61 <n-tab-pane name="Overview" tab="Overview" display-directive="show">
62 <OverviewSection v-if="agent" :agent @updated="getAgent()" />
63 </n-tab-pane>
64 <n-tab-pane name="Vulnerabilities" tab="Vulnerabilities" display-directive="show:lazy">
65 <VulnerabilitiesGrid v-if="agent" :agent />
66 </n-tab-pane>
67 <n-tab-pane name="SCA" tab="SCA" display-directive="show:lazy">
68 <ScaTable v-if="agent" :agent />
69 </n-tab-pane>
70 <n-tab-pane name="Cases" tab="Cases" display-directive="show:lazy">
71 <!--
72 <AgentCases v-if="agent" :agent />
73 -->
74 <CasesList v-if="agent" :preset="{ type: 'hostname', value: agent.hostname }" hide-filters />
75 </n-tab-pane>
76 <n-tab-pane name="Artifacts" tab="Artifacts" display-directive="show:lazy">
77 <AgentFlowList v-if="agent" :agent />
78 </n-tab-pane>
79 <n-tab-pane name="Alerts" tab="Alerts" display-directive="show:lazy">
80 <!--
81 <AlertsList v-if="agent" :agent-hostname="agent.hostname" />
82 -->
83 <AlertsList
84 v-if="agent"
85 :preset="[{ type: 'assetName', value: agent.hostname }]"
86 :show-filters="false"
87 />
88 </n-tab-pane>
89 <n-tab-pane name="collect" tab="Collect" display-directive="show:lazy">
90 <ArtifactsCollect
91 v-if="agent"
92 :hostname="agent.hostname"
93 :artifacts
94 hide-hostname-field
95 @loaded-artifacts="artifacts = $event"
96 />
97 </n-tab-pane>
98 <n-tab-pane name="command" tab="Command" display-directive="show:lazy">
99 <ArtifactsCommand
100 v-if="agent"
101 :hostname="agent.hostname"
102 :artifacts
103 hide-hostname-field
104 @loaded-artifacts="artifacts = $event"
105 />
106 </n-tab-pane>
107 <n-tab-pane name="quarantine" tab="Quarantine" display-directive="show:lazy">
108 <ArtifactsQuarantine
109 v-if="agent"
110 :hostname="agent.hostname"
111 :artifacts
112 hide-hostname-field
113 @action-performed="getAgent()"
114 @loaded-artifacts="artifacts = $event"
115 />
116 </n-tab-pane>
117 <n-tab-pane name="active-response" tab="Active Response" display-directive="show:lazy">
118 <ActiveResponseAgent v-if="agent" :agent embedded />
119 </n-tab-pane>
120 <n-tab-pane name="file-collection" tab="File Collection" display-directive="show:lazy">
121 <div class="section">
122 <FileCollectionForm v-if="agent" :agent-id="agent.agent_id" />
123 </div>
124 </n-tab-pane>
125 <n-tab-pane name="data-store" tab="Data Store" display-directive="show:lazy">
126 <div class="section">
127 <AgentDataStoreTab v-if="agent" :agent />
128 </div>
129 </n-tab-pane>
130 </n-tabs>
131 </n-spin>
132 </n-card>
133 </div>
134 </template>
135
136 <script setup lang="ts">
137 import type { Agent } from "@/types/agents.d"
138 import type { Artifact } from "@/types/artifacts.d"
139 import { NButton, NCard, NSpin, NTabPane, NTabs, NTag, NTooltip, useDialog, useMessage } from "naive-ui"
140 import { computed, defineAsyncComponent, nextTick, onBeforeMount, ref } from "vue"
141 import { useRoute, useRouter } from "vue-router"
142 import Api from "@/api"
143 import { handleDeleteAgent, toggleAgentCritical } from "@/components/agents/utils"
144 import CardEntity from "@/components/common/cards/CardEntity.vue"
145 import Icon from "@/components/common/Icon.vue"
146 import { useNavigation } from "@/composables/useNavigation"
147 import { AgentStatus } from "@/types/agents.d"
148
149 const VulnerabilitiesGrid = defineAsyncComponent(
150 () => import("@/components/agents/vulnerabilities/VulnerabilitiesGrid.vue")
151 )
152 const ScaTable = defineAsyncComponent(() => import("@/components/agents/sca/ScaTable.vue"))
153 // const AlertsList = defineAsyncComponent(() => import("@/components/alerts/AlertsList.vue"))
154 const AlertsList = defineAsyncComponent(() => import("@/components/incidentManagement/alerts/AlertsList.vue"))
155 const OverviewSection = defineAsyncComponent(() => import("@/components/agents/OverviewSection.vue"))
156 // const AgentCases = defineAsyncComponent(() => import("@/components/agents/AgentCases.vue"))
157 const CasesList = defineAsyncComponent(() => import("@/components/incidentManagement/cases/CasesList.vue"))
158 const AgentFlowList = defineAsyncComponent(() => import("@/components/agents/agentFlow/AgentFlowList.vue"))
159 const ArtifactsCollect = defineAsyncComponent(() => import("@/components/artifacts/ArtifactsCollect.vue"))
160 const ArtifactsCommand = defineAsyncComponent(() => import("@/components/artifacts/ArtifactsCommand.vue"))
161 const ArtifactsQuarantine = defineAsyncComponent(() => import("@/components/artifacts/ArtifactsQuarantine.vue"))
162 const ActiveResponseAgent = defineAsyncComponent(() => import("@/components/activeResponse/ActiveResponseAgent.vue"))
163 const AgentDataStoreTab = defineAsyncComponent(() => import("@/components/agents/dataStore/AgentDataStoreTab.vue"))
164 const FileCollectionForm = defineAsyncComponent(
165 () => import("@/components/agents/fileCollection/FileCollectionForm.vue")
166 )
167
168 const ArrowIcon = "carbon:arrow-left"
169 const DeleteIcon = "ph:trash"
170
171 const { routeAgent } = useNavigation()
172 const message = useMessage()
173 const router = useRouter()
174 const dialog = useDialog()
175 const route = useRoute()
176 const loadingAgent = ref(false)
177 const upgradingAgent = ref(false)
178 const agent = ref<Agent | null>(null)
179 const agentId = ref<string | null>(null)
180
181 const artifacts = ref<Artifact[]>([])
182
183 const isOnline = computed(() => {
184 return agent.value?.wazuh_agent_status === AgentStatus.Active
185 })
186
187 function getAgent() {
188 if (agentId.value) {
189 loadingAgent.value = true
190
191 Api.agents
192 .getAgents(agentId.value)
193 .then(res => {
194 if (res.data.success) {
195 agent.value = res.data.agents[0] || null
196 } else {
197 message.error(res.data?.message || "An error occurred. Please try again later.")
198 routeAgent().navigate()
199 }
200 })
201 .catch(err => {
202 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
203 routeAgent().navigate()
204 })
205 .finally(() => {
206 loadingAgent.value = false
207 })
208 }
209 }
210
211 function upgradeWazuhAgent() {
212 if (agentId.value) {
213 upgradingAgent.value = true
214
215 Api.agents
216 .upgradeWazuhAgent(agentId.value)
217 .then(res => {
218 if (res.data.success) {
219 message.success(res.data?.message || "Agent upgraded successfully")
220 } else {
221 message.error(res.data?.message || "An error occurred. Please try again later.")
222 }
223 })
224 .catch(err => {
225 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
226 })
227 .finally(() => {
228 upgradingAgent.value = false
229 })
230 }
231 }
232
233 function toggleCritical(agentId: string, criticalStatus: boolean) {
234 toggleAgentCritical({
235 agentId,
236 criticalStatus,
237 message,
238 cbBefore: () => {
239 loadingAgent.value = true
240 },
241 cbSuccess: () => {
242 if (agent.value?.critical_asset !== undefined) {
243 agent.value.critical_asset = !criticalStatus
244 }
245 },
246 cbAfter: () => {
247 loadingAgent.value = false
248 }
249 })
250 }
251
252 function handleDelete() {
253 if (agent.value) {
254 handleDeleteAgent({
255 agent: agent.value,
256 message,
257 dialog,
258 cbBefore: () => {
259 loadingAgent.value = true
260 },
261 cbSuccess: () => {
262 routeAgent().navigate()
263 },
264 cbAfter: () => {
265 loadingAgent.value = false
266 }
267 })
268 }
269 }
270
271 onBeforeMount(() => {
272 if (route.params.id) {
273 agentId.value = route.params.id.toString()
274
275 nextTick(() => {
276 getAgent()
277 })
278 } else {
279 router.replace({ name: "Agents" }).catch(() => {})
280 }
281 })
282 </script>