main
vue 417 lines 11.7 KB
Raw
1 <template>
2 <div>
3 <CardEntity hoverable clickable :embedded class="@container" @click.stop="showDetails = true">
4 <template #headerMain>#{{ alert.id }}</template>
5 <template #headerExtra>
6 {{ formatDate(alert.timestamp_utc, dFormats.datetimesec) }}
7 </template>
8 <template #default>
9 <div class="flex flex-col gap-1">
10 {{ alert.rule_description }}
11 <p>
12 {{ alert.rule_groups }}
13 </p>
14 </div>
15 </template>
16 <template #mainExtra>
17 <div class="flex flex-wrap items-center gap-3">
18 <Badge type="splitted" color="primary">
19 <template #iconLeft>
20 <Icon :name="TargetIcon" :size="13" class="opacity-80!" />
21 </template>
22 <template #label>Fired times</template>
23 <template #value>
24 {{ alert.rule_firedtimes }}
25 </template>
26 </Badge>
27
28 <n-popover overlap placement="bottom-start">
29 <template #trigger>
30 <Badge type="splitted" color="primary" hint-cursor>
31 <template #iconLeft>
32 <Icon :name="AgentIcon" :size="13" class="opacity-80!" />
33 </template>
34 <template #label>Agent</template>
35 <template #value>
36 <div class="flex flex-wrap items-center gap-2">
37 {{ alert.agent_name }} / {{ alert.agent_labels_customer }}
38 <Icon :name="InfoIcon" :size="13" class="opacity-80!" />
39 </div>
40 </template>
41 </Badge>
42 </template>
43 <div class="flex flex-col gap-1">
44 <div class="box">
45 agent_id:
46 <code
47 class="text-primary cursor-pointer"
48 @click.stop="routeAgent(alert.agent_id).navigate()"
49 >
50 {{ alert.agent_id }}
51 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
52 </code>
53 </div>
54 <div class="box">
55 agent_ip:
56 <code>{{ alert.agent_ip }}</code>
57 </div>
58 <div class="box">
59 agent_name:
60 <code>{{ alert.agent_name }}</code>
61 </div>
62 <div class="box">
63 agent_labels_customer:
64 <code
65 class="text-primary cursor-pointer"
66 @click.stop="routeCustomer({ code: alert.agent_labels_customer }).navigate()"
67 >
68 {{ alert.agent_labels_customer }}
69 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
70 </code>
71 </div>
72 </div>
73 </n-popover>
74 <Badge type="splitted" color="primary">
75 <template #label>syslog</template>
76 <template #value>{{ alert.syslog_type }} / {{ alert.syslog_level }}</template>
77 </Badge>
78 <Badge type="splitted" color="primary" class="hidden! @2xl:flex!">
79 <template #label>manager</template>
80 <template #value>
81 {{ alert.manager_name }}
82 </template>
83 </Badge>
84 <Badge type="splitted" color="primary" class="hidden! @2xl:flex!">
85 <template #label>decoder</template>
86 <template #value>
87 {{ alert.decoder_name }}
88 </template>
89 </Badge>
90 <Badge type="splitted" color="primary" class="hidden! @2xl:flex!">
91 <template #label>source</template>
92 <template #value>
93 {{ alert.source }}
94 </template>
95 </Badge>
96 </div>
97 </template>
98 </CardEntity>
99
100 <n-modal
101 v-model:show="showDetails"
102 preset="card"
103 content-class="p-0!"
104 :style="{ maxWidth: 'min(800px, 90vw)', minHeight: 'min(600px, 90vh)', overflow: 'hidden' }"
105 :title="`Alert: ${alert.id}`"
106 :bordered="false"
107 segmented
108 >
109 <n-tabs type="line" animated :tabs-padding="24">
110 <n-tab-pane name="Agent" tab="Agent" display-directive="show">
111 <div v-if="agentProperties" class="grid-auto-fit-200 grid gap-2 p-6 pt-3">
112 <CardKV v-for="(value, key) of agentProperties" :key>
113 <template #key>
114 {{ key }}
115 </template>
116 <template #value>
117 <template v-if="key === 'agent_id'">
118 <code
119 class="text-primary cursor-pointer"
120 @click.stop="routeAgent(`${value}`).navigate()"
121 >
122 {{ value }}
123 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
124 </code>
125 </template>
126 <template v-else-if="key === 'agent_labels_customer'">
127 <code
128 class="text-primary cursor-pointer"
129 @click.stop="
130 routeCustomer(value ? { code: value.toString() } : undefined).navigate()
131 "
132 >
133 {{ value }}
134 <Icon :name="LinkIcon" :size="13" class="relative top-0.5" />
135 </code>
136 </template>
137 <template v-else>
138 {{ value || "-" }}
139 </template>
140 </template>
141 </CardKV>
142 </div>
143 </n-tab-pane>
144
145 <template v-if="!useDetailsTab">
146 <n-tab-pane
147 v-for="tabCard of tabsCards"
148 :key="tabCard.tab"
149 :name="tabCard.tab"
150 :tab="tabCard.tab"
151 display-directive="show"
152 >
153 <div v-if="tabCard.properties" class="grid-auto-fit-200 grid gap-2 p-6 pt-3">
154 <CardKV v-for="(value, key) of tabCard.properties" :key>
155 <template #key>
156 {{ key }}
157 </template>
158 <template #value>
159 {{ value || "-" }}
160 </template>
161 </CardKV>
162 </div>
163 </n-tab-pane>
164
165 <n-tab-pane name="DNS" tab="DNS" display-directive="show">
166 <div class="px-6 pt-3">
167 <CardKV v-if="alert.data_dns_answers">
168 <template #key>data_dns_answers</template>
169 <template #value>
170 <CodeSource :code="alert.data_dns_answers" :decode="false" />
171 </template>
172 </CardKV>
173 </div>
174 <div v-if="dnsProperties" class="grid-auto-fit-200 grid gap-2 p-6 pt-3">
175 <CardKV v-for="(value, key) of dnsProperties" :key>
176 <template #key>
177 {{ key }}
178 </template>
179 <template #value>
180 {{ value || "-" }}
181 </template>
182 </CardKV>
183 </div>
184 </n-tab-pane>
185
186 <n-tab-pane name="GL2" tab="GL2" display-directive="show">
187 <div class="px-6 pt-3">
188 <CardKV v-if="alert.gl2_processing_error">
189 <template #key>gl2_processing_error</template>
190 <template #value>
191 {{ alert.gl2_processing_error }}
192 </template>
193 </CardKV>
194 </div>
195 <div v-if="gl2Properties" class="grid-auto-fit-200 grid gap-2 p-6 pt-3">
196 <CardKV v-for="(value, key) of gl2Properties" :key>
197 <template #key>
198 {{ key }}
199 </template>
200 <template #value>
201 {{ value || "-" }}
202 </template>
203 </CardKV>
204 </div>
205 </n-tab-pane>
206
207 <n-tab-pane v-if="alert.message" name="Message" tab="Message" display-directive="show">
208 <div class="p-6 pt-3">
209 <CodeSource :code="alert.message" :decode="false" />
210 </div>
211 </n-tab-pane>
212
213 <n-tab-pane v-if="alert.location" name="Location" tab="Location" display-directive="show">
214 <div class="p-6 pt-3">
215 <CodeSource :code="alert.location" :decode="false" />
216 </div>
217 </n-tab-pane>
218
219 <n-tab-pane v-if="alert.streams?.length" name="Streams" tab="Streams" display-directive="show">
220 <div class="flex flex-wrap gap-3 p-6 pt-3">
221 <ul>
222 <li v-for="stream of alert.streams" :key="stream">
223 <code>{{ stream }}</code>
224 </li>
225 </ul>
226 </div>
227 </n-tab-pane>
228 </template>
229
230 <n-tab-pane name="Details" tab="Details" display-directive="show:lazy">
231 <div class="p-6 pt-3">
232 <CodeSource :code="alert" lang="json" :decode="false" />
233 </div>
234 </n-tab-pane>
235 </n-tabs>
236 </n-modal>
237 </div>
238 </template>
239
240 <script setup lang="ts">
241 import type { MitreEventDetails } from "@/types/mitre.d"
242 import _pick from "lodash/pick"
243 import { NModal, NPopover, NTabPane, NTabs } from "naive-ui"
244 import { computed, defineAsyncComponent, ref, toRefs } from "vue"
245 import Badge from "@/components/common/Badge.vue"
246 import CardEntity from "@/components/common/cards/CardEntity.vue"
247 import CardKV from "@/components/common/cards/CardKV.vue"
248 import Icon from "@/components/common/Icon.vue"
249 import { useNavigation } from "@/composables/useNavigation"
250 import { useSettingsStore } from "@/stores/settings"
251 import { formatDate } from "@/utils/format"
252
253 const props = defineProps<{
254 alert: MitreEventDetails
255 hideActions?: boolean
256 embedded?: boolean
257 useDetailsTab?: boolean
258 }>()
259 const CodeSource = defineAsyncComponent(() => import("@/components/common/CodeSource.vue"))
260
261 const { alert, embedded, useDetailsTab } = toRefs(props)
262
263 const InfoIcon = "carbon:information"
264 const TargetIcon = "zondicons:target"
265 const AgentIcon = "carbon:police"
266 const LinkIcon = "carbon:launch"
267
268 const { routeCustomer, routeAgent } = useNavigation()
269 const showDetails = ref(false)
270 const dFormats = useSettingsStore().dateFormat
271
272 const tabsCards = computed(() => [
273 {
274 tab: "Host",
275 properties: _pick(alert.value, [
276 "data_host_architecture",
277 "data_host_id",
278 "data_host_mac",
279 "data_host_name",
280 "data_host_hostname",
281 "data_host_containerized",
282 "data_host_ip",
283 "data_host_os_codename",
284 "data_host_os_family",
285 "data_host_os_kernel",
286 "data_host_os_name",
287 "data_host_os_platform",
288 "data_host_os_type",
289 "data_host_os_version"
290 ])
291 },
292 {
293 tab: "Network",
294 properties: _pick(alert.value, [
295 "data_network_protocol",
296 "data_network_transport",
297 "data_network_type",
298 "data_network_bytes",
299 "data_network_direction",
300 "data_network_community_id",
301 "traffic_direction"
302 ])
303 },
304 {
305 tab: "Event",
306 properties: _pick(alert.value, [
307 "data_event_category",
308 "data_event_dataset",
309 "data_event_duration",
310 "data_event_end",
311 "data_event_kind",
312 "data_event_start",
313 "data_event_type",
314 "data_type"
315 ])
316 },
317 {
318 tab: "Timestamp",
319 properties: _pick(alert.value, ["timestamp", "timestamp_utc", "data_@timestamp", "msg_timestamp"])
320 },
321 {
322 tab: "Source",
323 properties: _pick(alert.value, ["data_source_ip", "data_source_port", "data_source_bytes"])
324 },
325 {
326 tab: "Destination",
327 properties: _pick(alert.value, ["data_destination_ip", "data_destination_port", "data_destination_bytes"])
328 },
329 {
330 tab: "Client",
331 properties: _pick(alert.value, ["data_client_ip", "data_client_port", "data_client_bytes"])
332 },
333 {
334 tab: "Server",
335 properties: _pick(alert.value, ["data_server_ip", "data_server_port", "data_server_bytes"])
336 },
337 {
338 tab: "Cluster",
339 properties: _pick(alert.value, ["cluster_name", "cluster_node"])
340 },
341 {
342 tab: "Rule",
343 properties: _pick(alert.value, [
344 "rule_id",
345 "rule_level",
346 "rule_mail",
347 "rule_mitre_id",
348 "rule_mitre_tactic",
349 "rule_mitre_technique",
350 "rule_description",
351 "rule_firedtimes",
352 "rule_groups",
353 "rule_group1",
354 "rule_group2",
355 "rule_group3"
356 ])
357 }
358 ])
359
360 const agentProperties = computed(() => {
361 return _pick(alert.value, [
362 "agent_id",
363 "agent_name",
364 "agent_ip",
365 "data_agent_id",
366 "data_agent_name",
367 "data_agent_type",
368 "data_agent_version",
369 "data_agent_ephemeral_id",
370 "agent_labels_customer"
371 ])
372 })
373
374 const dnsProperties = computed(() => {
375 return _pick(alert.value, [
376 "data_dns_answers_count",
377 "data_dns_authorities_count",
378 "data_dns_flags_authentic_data",
379 "data_dns_flags_authoritative",
380 "data_dns_flags_checking_disabled",
381 "data_dns_flags_recursion_available",
382 "data_dns_flags_recursion_desired",
383 "data_dns_flags_truncated_response",
384 "data_dns_header_flags",
385 "data_dns_id",
386 "data_dns_op_code",
387 "data_dns_opt_do",
388 "data_dns_opt_ext_rcode",
389 "data_dns_opt_udp_size",
390 "data_dns_opt_version",
391 "data_dns_question_class",
392 "data_dns_question_etld_plus_one",
393 "data_dns_question_name",
394 "data_dns_question_registered_domain",
395 "data_dns_question_subdomain",
396 "data_dns_question_top_level_domain",
397 "data_dns_question_type",
398 "data_dns_resolved_ip",
399 "data_dns_response_code",
400 "data_dns_type",
401 "dns_query",
402 "dns_response_code",
403 "dns_answer"
404 ])
405 })
406
407 const gl2Properties = computed(() => {
408 return _pick(alert.value, [
409 "gl2_remote_ip",
410 "gl2_source_node",
411 "gl2_accounted_message_size",
412 "gl2_remote_port",
413 "gl2_source_input",
414 "gl2_message_id"
415 ])
416 })
417 </script>