Sysmon config cont (#420)
* fix: clarify upload step in sysmon config deployment * feat: update sysmon config page --------- Co-authored-by: Davide Di Modica <webmaster.ddm@gmail.com>
taylor_socfortress committed
Mar 7, 2025 at 14:04 UTC
ae49996c5ef554439b813bc3e42126122c84ed4d
2 files changed
+92
-4
backend/app/active_response/services/sysmon_config.py
+1
-1
@@ -198,7 +198,7 @@ async def deploy_sysmon_config_to_worker(customer_code: str, session: AsyncSessi
198
error_detail=str(endpoint_error),
199
)
200
201
- # Step 4: Upload to Wazuh
201
+ # Step 4: Upload to Wazuh via the agent group shared folder
202
success, response_data, error_text = await upload_to_wazuh(endpoint, customer_code, temp_path)
203
204
if success:
frontend/src/views/agents/SysmonConfig.vue
+91
-3
@@ -34,6 +34,20 @@
34
<template v-else>
35
<n-empty v-if="!loadingList" description="No items found" class="h-48 justify-center" />
36
</template>
37
+ <n-dropdown
38
+ v-if="hasCustomersAvailable"
39
+ placement="bottom-start"
40
+ trigger="click"
41
+ :options="customersOptions"
42
+ @select="newConfig($event)"
43
+ >
44
+ <n-button secondary class="!mt-4 !w-full" size="large">
45
+ <template #icon>
46
+ <Icon :size="18" :name="NewConfigIcon" />
47
+ </template>
48
+ <span class="ml-2">Add new Configuration</span>
49
+ </n-button>
50
+ </n-dropdown>
51
</n-spin>
52
</template>
53
<template #main-toolbar>
@@ -75,7 +89,13 @@
89
<span class="@xs:flex hidden">Upload</span>
90
</div>
91
</n-button>
78
- <n-button :loading="deployingConfig" size="small" type="success" @click="deployConfig()">
92
+ <n-button
93
+ :loading="deployingConfig"
94
+ size="small"
95
+ type="success"
96
+ :disabled="!currentConfig.config_content"
97
+ @click="deployConfig()"
98
+ >
99
<div class="flex items-center gap-2">
100
<Icon :name="DeployIcon" />
101
<span class="@xs:flex hidden">Deploy</span>
@@ -108,7 +128,9 @@
128
129
<script setup lang="ts">
130
import type { XMLEditorCtx } from "@/components/common/XMLEditor.vue"
131
+import type { Customer } from "@/types/customers"
132
import type { ConfigContent } from "@/types/sysmonConfig.d"
133
+import type { DropdownMixedOption } from "naive-ui/es/dropdown/src/interface"
134
import Api from "@/api"
135
import CardEntity from "@/components/common/cards/CardEntity.vue"
136
import Icon from "@/components/common/Icon.vue"
@@ -116,8 +138,8 @@ import SegmentedPage from "@/components/common/SegmentedPage.vue"
138
import XMLEditor from "@/components/common/XMLEditor.vue"
139
import { useGoto } from "@/composables/useGoto"
140
import _clone from "lodash/cloneDeep"
119
-import { NButton, NEmpty, NSpin, useMessage } from "naive-ui"
120
-import { computed, onBeforeMount, ref } from "vue"
141
+import { NButton, NDropdown, NEmpty, NSpin, useMessage } from "naive-ui"
142
+import { computed, h, onBeforeMount, ref } from "vue"
143
144
const message = useMessage()
145
const { gotoCustomer } = useGoto()
@@ -134,9 +156,74 @@ const RedoIcon = "carbon:redo"
156
const LinkIcon = "carbon:launch"
157
const DeployIcon = "carbon:deploy"
158
const UploadIcon = "carbon:cloud-upload"
159
+const NewConfigIcon = "carbon:document-add"
160
161
const isDirty = computed(() => currentConfig.value?.config_content !== backupConfig.value?.config_content)
162
163
+const loadingCustomersList = ref(false)
164
+const customersList = ref<Customer[]>([])
165
+const hasCustomersAvailable = computed<boolean>(
166
+ () => !!customersList.value.filter(o => !customers.value.includes(o.customer_code)).length
167
+)
168
+
169
+const customersOptions = computed(() => {
170
+ const options: DropdownMixedOption[] = []
171
+
172
+ options.push({
173
+ label: () => h("div", { class: "pl-2" }, `Select a Customer${loadingCustomersList.value ? "..." : ""}`),
174
+ type: "group",
175
+ children: customersList.value
176
+ .filter(o => !customers.value.includes(o.customer_code))
177
+ .map(o => ({
178
+ label: `#${o.customer_code} - ${o.customer_name}`,
179
+ key: o.customer_code
180
+ }))
181
+ })
182
+
183
+ return options
184
+})
185
+
186
+function getCustomers() {
187
+ loadingCustomersList.value = true
188
+
189
+ Api.customers
190
+ .getCustomers()
191
+ .then(res => {
192
+ if (res.data.success) {
193
+ customersList.value = res.data?.customers || []
194
+ } else {
195
+ message.warning(res.data?.message || "An error occurred. Please try again later.")
196
+ }
197
+ })
198
+ .catch(err => {
199
+ message.error(err.response?.data?.message || "An error occurred. Please try again later.")
200
+ })
201
+ .finally(() => {
202
+ loadingCustomersList.value = false
203
+ })
204
+}
205
+
206
+function newConfig(customerCode: string) {
207
+ customers.value.push(customerCode)
208
+ currentConfig.value = {
209
+ customer_code: customerCode,
210
+ config_content: `<Sysmon schemaversion="4.60">
211
+ <EventFiltering>
212
+ <RuleGroup groupRelation="or"></RuleGroup>
213
+ </EventFiltering>
214
+</Sysmon>`
215
+ }
216
+ backupConfig.value = {
217
+ customer_code: customerCode,
218
+ config_content: `<Sysmon schemaversion="4.60">
219
+ <EventFiltering>
220
+ <RuleGroup groupRelation="or"></RuleGroup>
221
+ </EventFiltering>
222
+</Sysmon>`
223
+ }
224
+ uploadConfigFile()
225
+}
226
+
227
function loadConfig(customerCode: string) {
228
if (customerCode !== currentConfig.value?.customer_code) {
229
getConfigContent(customerCode)
@@ -239,5 +326,6 @@ function deployConfig() {
326
327
onBeforeMount(() => {
328
getList()
329
+ getCustomers()
330
})
331
</script>