Skip to content

Commit 6e5a098

Browse files
committed
rule creation and edit templates
1 parent bc42105 commit 6e5a098

File tree

6 files changed

+178
-92
lines changed

6 files changed

+178
-92
lines changed

sentinel-kit_server_frontend/src/App.vue

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,21 @@
1515
</span>
1616
</RouterLink>
1717
</nav>
18+
19+
20+
<button
21+
@click="logout"
22+
class="bg-red-500 hover:bg-red-600 text-white font-bold py-2 px-4 rounded-lg transition duration-150 ease-in-out flex items-center"
23+
title="Log out"
24+
>
25+
<svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path></svg>
26+
Log out
27+
</button>
28+
29+
1830
</aside>
1931

2032
<div :class="{ 'ml-64': !isCollapsed, 'ml-20': isCollapsed }" class="flex-1 flex flex-col transition-all duration-300 ease-in-out">
21-
<div v-if="isLoggedIn"><Header /></div>
22-
2333
<main class="p-6 flex-1 overflow-y-auto">
2434
<RouterView />
2535
</main>
@@ -29,9 +39,9 @@
2939

3040
<script setup>
3141
import { onMounted, ref } from 'vue';
32-
import { RouterView, RouterLink } from 'vue-router';
33-
import Header from './components/Header.vue';
42+
import { useRouter, RouterView, RouterLink } from 'vue-router';
3443
44+
const router = useRouter();
3545
const isLoggedIn = ref(false);
3646
const isCollapsed = ref(true);
3747
@@ -40,6 +50,10 @@ onMounted(() => {
4050
isLoggedIn.value = !!token;
4151
});
4252
53+
const logout = () => {
54+
router.push({ name: 'Logout' });
55+
};
56+
4357
const menuItems = [
4458
{ name: 'Home', icon: 'mdi-light--home', route: 'Home' },
4559
{ name: 'Dashboard', icon: 'svg-spinners--blocks-wave', route: 'Home' },
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<template>
2+
<div class="monaco-wrapper h-full border border-gray-300 rounded-lg overflow-hidden">
3+
<DiffEditor
4+
v-if="isDiffMode || isLatestDiffToggled"
5+
:original="originalContent"
6+
:modified="modelValue"
7+
language="yaml"
8+
theme="vs-light"
9+
:options="diffOptions"
10+
class="monaco-container"
11+
/>
12+
13+
<VueMonacoEditor
14+
v-else
15+
:value="modelValue"
16+
@update:value="emit('update:modelValue', $event)"
17+
language="yaml"
18+
theme="vs-light"
19+
:options="editorOptions"
20+
:readOnly="readOnly"
21+
class="monaco-container"
22+
/>
23+
</div>
24+
</template>
25+
26+
<script setup>
27+
import { computed } from 'vue';
28+
import { DiffEditor, VueMonacoEditor } from '@guolao/vue-monaco-editor';
29+
30+
const props = defineProps({
31+
modelValue: {
32+
type: String,
33+
default: '',
34+
},
35+
originalContent: {
36+
type: String,
37+
default: '',
38+
},
39+
isDiffMode: {
40+
type: Boolean,
41+
default: false,
42+
},
43+
isLatestDiffToggled: {
44+
type: Boolean,
45+
default: false,
46+
},
47+
readOnly: {
48+
type: Boolean,
49+
default: false,
50+
}
51+
});
52+
53+
const emit = defineEmits(['update:modelValue']);
54+
55+
const editorOptions = computed(() => ({
56+
automaticLayout: true,
57+
minimap: { enabled: true },
58+
readOnly: props.readOnly,
59+
tabSize: 2,
60+
scrollBeyondLastLine: false,
61+
wordWrap: 'on',
62+
}));
63+
64+
const diffOptions = computed(() => ({
65+
automaticLayout: true,
66+
minimap: { enabled: true },
67+
readOnly: true,
68+
tabSize: 2,
69+
scrollBeyondLastLine: false,
70+
wordWrap: 'on',
71+
renderSideBySide: true,
72+
}));
73+
</script>
74+
75+
<style scoped>
76+
.monaco-container {
77+
height: 100%;
78+
width: 100%;
79+
}
80+
</style>

sentinel-kit_server_frontend/src/main.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ const router = createRouter({
5353
name: 'RuleEdit',
5454
component: () => import('./views/RuleEdit.vue'),
5555
meta: { requiresAuth: true }
56+
},
57+
{
58+
path: '/rules/create',
59+
name: 'RuleCreate',
60+
component: () => import('./views/RuleCreate.vue'),
61+
meta: { requiresAuth: true }
5662
}
5763

5864
]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<div>
3+
<h3 class="text-left text-lg font-semibold mb-4 text-gray-700">New sigma rule creation</h3>
4+
<RuleEditor
5+
v-model="newRuleContent"
6+
:read-only="false"
7+
class="h-96 w-full"
8+
/>
9+
<button @click="saveRule">Save</button>
10+
</div>
11+
</template>
12+
13+
<script setup>
14+
import { ref } from 'vue';
15+
import RuleEditor from '../components/RuleEditor.vue';
16+
17+
const newRuleContent = ref('# https://github.com/SigmaHQ/sigma/wiki/Rule-Creation-Guide\n\ntitle: a short capitalised title with less than 50 characters\nid: generate one here https://www.uuidgenerator.net/version4\nstatus: experimental\ndescription: A description of what your rule is meant to detect \nreferences:\n - A list of all references that can help a reader or analyst understand the meaning of a triggered rule\ntags:\n - attack.execution # example MITRE ATT&CK category\n - attack.t1059 # example MITRE ATT&CK technique id\n - car.2014-04-003 # example CAR id\nauthor: Michael Haag, Florian Roth, Markus Neis # example, a list of authors\ndate: 2018/04/06 # Rule date\nlogsource: # important for the field mapping in predefined or your additional config files\n category: process_creation # In this example we choose the category \'process_creation\'\n product: windows # the respective product\ndetection:\n selection:\n FieldName: \'StringValue\'\n FieldName: IntegerValue\n FieldName|modifier: \'Value\'\n condition: selection\nfields:\n - fields in the log source that are important to investigate further\nfalsepositives:\n - describe possible false positive conditions to help the analysts in their investigation\nlevel: one of five levels (informational, low, medium, high, critical)');
18+
19+
function saveRule() {
20+
console.log('Contenu de la nouvelle règle:', newRuleContent.value);
21+
}
22+
</script>

sentinel-kit_server_frontend/src/views/RuleEdit.vue

Lines changed: 49 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -58,37 +58,24 @@
5858
</div>
5959

6060
<div class="rule-editing w-3/4 p-4">
61-
<h3 class="text-left text-lg font-semibold mb-4 text-gray-700">{{details?.title }}</h3>
62-
<div class="monaco-wrapper h-full border border-gray-300 rounded-lg overflow-hidden">
63-
64-
<DiffEditor
65-
v-if="isDiffMode || (isLatestVersion(currentVersionId) && isLatestDiffToggled)"
66-
:original="isLatestDiffToggled ? previousOfLatestContent : previousVersionContent"
67-
:modified="currentSelectedContent"
68-
language="yaml"
69-
theme="vs-light"
70-
:options="diffOptions"
71-
class="monaco-container"
72-
/>
73-
74-
<VueMonacoEditor
75-
v-else
76-
v-model:value="code"
77-
language="yaml"
78-
theme="vs-light"
79-
:options="editorOptions"
80-
class="monaco-container"
81-
/>
82-
61+
<h3 class="text-left text-lg font-semibold mb-4 text-gray-700">{{details?.title }}</h3>
62+
63+
<RuleEditor
64+
v-model="code"
65+
:is-diff-mode="isDiffMode"
66+
:is-latest-diff-toggled="isLatestDiffToggled"
67+
:original-content="isLatestDiffToggled ? previousOfLatestContent : previousVersionContent"
68+
:read-only="isDiffMode || isLatestDiffToggled"
69+
class="h-full"
70+
/>
8371
</div>
84-
</div>
8572
</div>
8673
</template>
8774

8875
<script setup>
8976
import { ref, computed, onMounted } from 'vue';
90-
import { DiffEditor, VueMonacoEditor } from '@guolao/vue-monaco-editor';
9177
import { useRoute } from 'vue-router';
78+
import RuleEditor from '../components/RuleEditor.vue';
9279
9380
const BASE_URL = import.meta.env.VITE_API_BASE_URL;
9481
const route = useRoute();
@@ -102,26 +89,6 @@ const previousVersionContent = ref('');
10289
const isDiffMode = ref(false);
10390
const isLatestDiffToggled = ref(false);
10491
105-
const editorOptions = computed(() => ({
106-
automaticLayout: true,
107-
minimap: { enabled: true },
108-
readOnly: false,
109-
tabSize: 2,
110-
scrollBeyondLastLine: false,
111-
wordWrap: 'on',
112-
}));
113-
114-
const diffOptions = computed(() => ({
115-
automaticLayout: true,
116-
minimap: { enabled: true },
117-
readOnly: true,
118-
tabSize: 2,
119-
scrollBeyondLastLine: false,
120-
wordWrap: 'on',
121-
renderSideBySide: true,
122-
}));
123-
124-
12592
const latestVersionId = computed(() => {
12693
return details.value?.versions?.length > 0 ? details.value.versions[0].id : null;
12794
});
@@ -168,11 +135,11 @@ const loadVersionContent = (version) => {
168135
isLatestDiffToggled.value = false;
169136
}
170137
171-
isDiffMode.value = !isLatest && !isInitial;
172-
138+
isDiffMode.value = !isLatest && !isInitial;
139+
173140
if (isDiffMode.value && details.value?.versions) {
174141
const versions = details.value.versions;
175-
const selectedIndex = versions.findIndex(v => v.id === version.id);
142+
const selectedIndex = versions.findIndex(v => v.id === version.id);
176143
const previousVersion = versions[selectedIndex + 1];
177144
178145
if (previousVersion) {
@@ -187,42 +154,42 @@ const loadVersionContent = (version) => {
187154
188155
189156
const fetchRuleData = () => {
190-
const ruleId = route.params.id;
191-
192-
if (!ruleId) {
193-
console.error('Erreur: ID de la règle non trouvé.');
194-
code.value = "Erreur de chargement: ID manquant.";
195-
return;
196-
}
197-
198-
fetch(`${BASE_URL}/rules/sigma/${ruleId}/details`, {
199-
method: 'GET',
200-
headers: {
201-
'Content-Type': 'application/json',
202-
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`,
203-
},
204-
})
205-
.then(response => {
206-
if (!response.ok) {
207-
throw new Error(`Erreur HTTP! Status: ${response.status}`);
208-
}
209-
return response.json();
210-
})
211-
.then(data => {
212-
details.value = data;
213-
214-
if (data && data.versions && data.versions.length > 0) {
215-
const latestVersion = data.versions[0];
216-
loadVersionContent(latestVersion);
217-
} else {
218-
details.value = { versions: [] };
219-
code.value = "Aucune version de règle trouvée.";
157+
const ruleId = route.params.id;
158+
159+
if (!ruleId) {
160+
console.error('Erreur: ID de la règle non trouvé.');
161+
code.value = "Erreur de chargement: ID manquant.";
162+
return;
163+
}
164+
165+
fetch(`${BASE_URL}/rules/sigma/${ruleId}/details`, {
166+
method: 'GET',
167+
headers: {
168+
'Content-Type': 'application/json',
169+
'Authorization': `Bearer ${localStorage.getItem('auth_token')}`,
170+
},
171+
})
172+
.then(response => {
173+
if (!response.ok) {
174+
throw new Error(`Erreur HTTP! Status: ${response.status}`);
220175
}
221-
})
222-
.catch(error => {
223-
console.error('Error while retrieving rule\'s data:', error);
224-
code.value = `Error loading: ${error.message}`;
225-
});
176+
return response.json();
177+
})
178+
.then(data => {
179+
details.value = data;
180+
181+
if (data && data.versions && data.versions.length > 0) {
182+
const latestVersion = data.versions[0];
183+
loadVersionContent(latestVersion);
184+
} else {
185+
details.value = { versions: [] };
186+
code.value = "Aucune version de règle trouvée.";
187+
}
188+
})
189+
.catch(error => {
190+
console.error('Error while retrieving rule\'s data:', error);
191+
code.value = `Error loading: ${error.message}`;
192+
});
226193
};
227194
228195
onMounted(fetchRuleData);
@@ -232,9 +199,4 @@ onMounted(fetchRuleData);
232199
.h-screen-minus-header {
233200
height: calc(100vh - 64px);
234201
}
235-
236-
.monaco-container {
237-
height: 100%;
238-
width: 100%;
239-
}
240202
</style>

sentinel-kit_server_frontend/src/views/RulesList.vue

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<template>
2-
<h1 class="text-left mb-4">Detection rules list</h1>
2+
<button class="btn btn-primary float-right mb-4" @click="$router.push({ name: 'RuleCreate' })">Create new rule</button>
3+
<h1 class="text-left mb-4 float-left">Detection rules list</h1>
4+
<br class="clear-both" />
35
<div v-if="rules.length > 0" class="space-y-4">
46
<div class="flex flex-wrap items-center gap-4 p-4 border rounded-lg bg-gray-50 shadow-sm">
57

0 commit comments

Comments
 (0)