Skip to content

Commit

Permalink
Merge pull request #545 from Security-Onion-Solutions/jertel/bt
Browse files Browse the repository at this point in the history
toggle full query view
  • Loading branch information
jertel authored Jun 13, 2024
2 parents 5bb5953 + 115d680 commit 1f28998
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 3 deletions.
7 changes: 6 additions & 1 deletion html/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ <h4 v-if="loaded" :data-aid="'event_total_' + category">{{ i18n.eventTotal }} {{
</v-row>
<v-row align="start">
<v-col cols="12" :md="isCategory('detections') ? 10 : 7">
<v-textarea :clearable="isAdvanced()" :auto-grow="isAdvanced()" :readonly="!isAdvanced()" :disabled="loading()" @change="notifyInputsChanged" class="mx-2" v-model="$data[isAdvanced() ? 'query' : 'queryName']" :hint="isAdvanced() ? i18n.queryHelp : ''" rows="1" persistent-hint prepend-icon="fa-search" @keydown.enter.prevent="hunt" id="hunt-query-input" :data-aid="'query_input_' + category">
<v-textarea :clearable="isAdvanced()" :auto-grow="isAdvanced()" :readonly="!isAdvanced()" :disabled="loading()" @input="queryAltered = true" @change="queryModified" class="mx-2" v-model="$data[getDisplayedQueryVar()]" :hint="isAdvanced() ? i18n.queryHelp : ''" rows="1" persistent-hint prepend-icon="fa-search" @keydown.enter.prevent="submitQuery" id="hunt-query-input" :data-aid="'query_input_' + category">
<template v-slot:prepend-inner>
<v-menu dense bottom three-line offset-y>
<template v-slot:activator="{ on: menu }">
Expand Down Expand Up @@ -449,6 +449,11 @@ <h4 v-if="loaded" :data-aid="'event_total_' + category">{{ i18n.eventTotal }} {{
</v-list>
</v-menu>
</template>
<template v-if="isAdvanced()" v-slot:append>
<v-btn small icon id="toggle-full-query-button" :title="i18n.toggleFullQueryHelp" @click="showFullQuery = !showFullQuery" :disabled="queryAltered" :data-aid="'toggle_full_query_' + category">
<v-icon>fa-ellipsis</v-icon>
</v-btn>
</template>
<template v-if="!isCategory('hunt')" v-slot:append-outer>
<v-btn small icon id="switch-to-hunt-button" :title="i18n.huntHelp" @click="switchToHunt()" :data-aid="'nav_hunt_' + category">
<v-icon>fa-crosshairs</v-icon>
Expand Down
1 change: 1 addition & 0 deletions html/js/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,7 @@ const i18n = {
'so-sensor-keywords': 'Forward, Sensor, Sensoroni, Stenographer',
'so-standalone': 'Standalone',
'so-standalone-keywords': 'Elastic, Elasticsearch, Fleet, Forward, Ingest, Manager, Master, Search, Sensor, Sensoroni, Soc, Stenographer, Web',
toggleFullQueryHelp: 'Toggles between showing the full query or only the search filter. Disabled if query has been modified.',
showPieChart: 'Show pie chart',
showBarChart: 'Show bar chart',
showSankeyChart: 'Show Sankey diagram',
Expand Down
38 changes: 36 additions & 2 deletions html/js/routes/hunt.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,10 @@ const huntComponent = {
params: null,
category: '',
advanced: false,
queryAltered: false,
query: '',
querySearch: '',
queryRemainder: '',
queries: [],
queryBaseFilter: "",
queryName: '',
Expand Down Expand Up @@ -99,6 +102,7 @@ const huntComponent = {
mruCases: [],

autohunt: true,
showFullQuery: true,

filterRouteInclude: "",
filterRouteExclude: "",
Expand Down Expand Up @@ -289,6 +293,19 @@ const huntComponent = {
return [];
}
},
reconstructQuery() {
if (this.isAdvanced() && !this.showFullQuery) {
this.query = this.querySearch + " " + this.queryRemainder;
}
},
submitQuery() {
this.reconstructQuery();
this.hunt();
},
queryModified() {
this.reconstructQuery();
return this.notifyInputsChanged();
},
notifyInputsChanged(replaceHistory = false) {
var hunted = false;
this.toggleQuickAction();
Expand Down Expand Up @@ -725,8 +742,21 @@ const huntComponent = {
}
return item;
},
getDisplayedQueryVar() {
if (this.isAdvanced()) {
if (this.showFullQuery) {
return 'query'
} else {
return 'querySearch'
}
}
return 'queryName'
},
obtainQueryDetails() {
this.queryAltered = false;
this.queryName = "";
this.querySearch = "";
this.queryRemainder = "";
this.queryFilters = [];
this.queryGroupBys = [];
this.queryGroupByOptions = [];
Expand Down Expand Up @@ -765,15 +795,19 @@ const huntComponent = {
}

if (segments.length > 0) {
var search = segments[0].trim();
this.querySearch = segments[0].trim();
if (segments.length > 1) {
// Used for reconstructing full query from simplified filter-only view
this.queryRemainder = this.query.substring(segmentDelimIdx);
}
var matchingQueryName = this.i18n.custom;
for (var i = 0; i < this.queries.length; i++) {
if (this.query == this.queries[i].query) {
matchingQueryName = this.queries[i].name;
}
}
this.queryName = matchingQueryName;
search.split(" AND ").forEach(function(item, index) {
this.querySearch.split(" AND ").forEach(function(item, index) {
item = item.trim();
if (item.length > 0 && item != "*") {
route.queryFilters.push(item);
Expand Down
58 changes: 58 additions & 0 deletions html/js/routes/hunt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,8 @@ test('obtainQueryDetails_blank', () => {
comp.query = ""
comp.obtainQueryDetails();
expect(comp.queryName).toBe("");
expect(comp.querySearch).toBe("");
expect(comp.queryRemainder).toBe("");
expect(comp.queryFilters).toStrictEqual([]);
expect(comp.queryGroupBys).toStrictEqual([]);
expect(comp.queryGroupByOptions).toStrictEqual([]);
Expand All @@ -710,6 +712,8 @@ test('obtainQueryDetails_queryOnly', () => {
comp.query = "foo: bar AND x:1"
comp.obtainQueryDetails();
expect(comp.queryName).toBe("Custom");
expect(comp.querySearch).toBe("foo: bar AND x:1");
expect(comp.queryRemainder).toBe("");
expect(comp.queryFilters).toStrictEqual(["foo: bar", "x:1"]);
expect(comp.queryGroupBys).toStrictEqual([]);
expect(comp.queryGroupByOptions).toStrictEqual([]);
Expand All @@ -720,6 +724,8 @@ test('obtainQueryDetails_queryGroupedOptionsTableSorted', () => {
comp.query = "foo: bar AND x:1 | groupby -opt1 z | groupby -optB r^ | sortby y | table x y z"
comp.obtainQueryDetails();
expect(comp.queryName).toBe("Custom");
expect(comp.querySearch).toBe("foo: bar AND x:1");
expect(comp.queryRemainder).toBe("| groupby -opt1 z | groupby -optB r^ | sortby y | table x y z");
expect(comp.queryFilters).toStrictEqual(["foo: bar", "x:1"]);
expect(comp.queryGroupBys).toStrictEqual([["z"], ["r^"]]);
expect(comp.queryGroupByOptions).toStrictEqual([["opt1"], ["optB"]]);
Expand All @@ -731,6 +737,8 @@ test('obtainQueryDetails_queryGroupedFilterPipe', () => {
comp.query = "foo: bar AND x:\"with | this\" | groupby z"
comp.obtainQueryDetails();
expect(comp.queryName).toBe("Custom");
expect(comp.querySearch).toBe("foo: bar AND x:\"with | this\"");
expect(comp.queryRemainder).toBe("| groupby z");
expect(comp.queryFilters).toStrictEqual(["foo: bar", "x:\"with | this\""]);
expect(comp.queryGroupBys).toStrictEqual([["z"]]);
expect(comp.queryGroupByOptions).toStrictEqual([[]]);
Expand All @@ -741,6 +749,8 @@ test('obtainQueryDetails_trickyEscapeSequence', () => {
comp.query = `process.working_directory:"C:\\\\Windows\\\\system32\\\\" | groupby host.name`;
comp.obtainQueryDetails();
expect(comp.queryName).toBe("Custom");
expect(comp.querySearch).toBe(`process.working_directory:"C:\\\\Windows\\\\system32\\\\"`);
expect(comp.queryRemainder).toBe("| groupby host.name");
expect(comp.queryFilters).toStrictEqual([`process.working_directory:"C:\\\\Windows\\\\system32\\\\"`]);
expect(comp.queryGroupBys).toStrictEqual([["host.name"]]);
expect(comp.queryGroupByOptions).toStrictEqual([[]]);
Expand Down Expand Up @@ -1286,4 +1296,52 @@ test('bulkAction - delete - confirm - failure', async () => {
expect(mock).toHaveBeenCalledWith('detection/bulk/delete', { ids: ["1", "3"] });
expect(comp.$root.showError).toHaveBeenCalledTimes(1);
expect(comp.$root.showError).toHaveBeenCalledWith(err);
});

test('reconstructQuery', () => {
comp.query = "bar: 'hi' | groupby x"
comp.obtainQueryDetails();
comp.reconstructQuery();
comp.querySearch = "foo: 1"

// Advanced mode and showFullQuery false so should reconstruct query using new custom filter
comp.advanced = true;
comp.showFullQuery = false;
comp.queryModified();
expect(comp.query).toBe("foo: 1 | groupby x");
});

test('queryModified', () => {
comp.$root.loading = true; // prevent any notification logic from running
comp.query = "bar: 'hi' | groupby x"
comp.obtainQueryDetails();
comp.querySearch = "foo: 1"

// Basic mode, should not reconstruct query
comp.queryModified();
expect(comp.query).toBe("bar: 'hi' | groupby x");

// Advanced mode, but showFullQuery is true so should not reconstruct query
comp.advanced = true;
comp.showFullQuery = true;
comp.queryModified();
expect(comp.query).toBe("bar: 'hi' | groupby x");

// Advanced mode and showFullQuery false so should reconstruct query using new custom filter
comp.advanced = true;
comp.showFullQuery = false;
comp.queryModified();
expect(comp.query).toBe("foo: 1 | groupby x");
});

test('getDisplayedQueryVar', () => {
expect(comp.getDisplayedQueryVar()).toBe('queryName');

comp.advanced = true;
comp.showFullQuery = true;
expect(comp.getDisplayedQueryVar()).toBe('query');

comp.advanced = true;
comp.showFullQuery = false;
expect(comp.getDisplayedQueryVar()).toBe('querySearch');
});

0 comments on commit 1f28998

Please sign in to comment.