@cryptotaxi247 / CoPilot / commits / ae49996c

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>