Skip to content

Commit

Permalink
Merge pull request #122 from Security-Onion-Solutions/kilo
Browse files Browse the repository at this point in the history
Avoid recursive Sankey diagrams by omitting datasets that lead to rec…
  • Loading branch information
jertel authored Jun 6, 2022
2 parents 974717c + aa59fc3 commit 9cc88b6
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 9 deletions.
1 change: 1 addition & 0 deletions html/js/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ const i18n = {
category: 'Category',

chartTitleBottom: 'Fewest Occurrences',
chartTitleIncomplete: '(partial)',
chartTitleTimeline: 'Timeline',
chartTitleTop: 'Most Occurrences',
cheatsheet: 'Cheat Sheet',
Expand Down
43 changes: 36 additions & 7 deletions html/js/routes/hunt.js
Original file line number Diff line number Diff line change
Expand Up @@ -988,6 +988,7 @@ const huntComponent = {
// chart_type: ChartJS type, such as pie, bar, sankey, etc.
// chart_options: ChartJS options. See setupBarChart, etc.
// chart_data: ChartJS labels and datasets. See setupBarChart and populateBarChart.
// is_incomplete: True if only partial data is rendered to avoid complete render failure.
var group = {};
group.title = fields.join(this.chartLabelFieldSeparator);
group.fields = [...fields];
Expand Down Expand Up @@ -1078,34 +1079,62 @@ const huntComponent = {
group.chart_type = "sankey";
group.chart_options = {};
group.chart_data = {};
this.setupSankeyChart(group.chart_options, group.chart_data, group.title);
this.applyLegendOption(group, groupIdx);

// Sankey has a unique dataset format, build it out here instead of using populateChartData().
// While building the new format, also calculate the max value across all nodes to be used
// as a scale factor for choosing colors of the sankey flows.
var flowMax = 0;
updateMaxMap = function(map, key, value) {
var updateMaxMap = function(map, key, value) {
var max = map[key];
if (!max) {
max = 0;
}
max = max + value;
maxFlowMap[key] = max;
map[key] = max;
flowMax = Math.max(flowMax, max);
}
};

var isRecursive = function(map, from, to, current, max) {
if (current > max || from == to) {
return true;
}

for (var i = 0; i < map.length; i++) {
var item = map[i];
if (item.from == to) {
if (isRecursive(map, item.from, item.to, current + 1, max)) {
return true;
}
}
}
return false;
};

var data = [];
var maxFlowMap = {};
group.data.forEach(function(item, index) {
for (var idx = 0; idx < group.fields.length - 1; idx++) {
var from = item[group.fields[idx]];
var to = item[group.fields[idx+1]];
updateMaxMap(maxFlowMap, from, item.count);
updateMaxMap(maxFlowMap, to, item.count);
var flow = { from: from, to: to, flow: item.count };
data.push(flow);

if (isRecursive(data, from, to, 0, group.fields.length)) {
group.is_incomplete = true;
data.pop();
} else {
updateMaxMap(maxFlowMap, from, item.count);
updateMaxMap(maxFlowMap, to, item.count);
}
}
});

if (group.is_incomplete) {
group.title += " " + this.i18n.chartTitleIncomplete;
}
this.setupSankeyChart(group.chart_options, group.chart_data, group.title);
this.applyLegendOption(group, groupIdx);

group.chart_data.datasets[0].data = data;
group.chart_data.flowMax = flowMax;
Vue.set(this.groupBys, groupIdx, group);
Expand Down
19 changes: 17 additions & 2 deletions html/js/routes/hunt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -408,14 +408,19 @@ test('displayPieChart', () => {

test('displaySankeyChart', () => {
var group = {chart_type: ''};
group.data = [{ count: 1, foo: 'moo', bar: 'mar' }, { count: 12, foo: 'moo', bar: 'car' }]
group.data = [{ count: 10, foo: 'mog', bar: 'mop' }, { count: 1, foo: 'moo', bar: 'mar' }, { count: 12, foo: 'moo', bar: 'car' }, { count: 2, foo: 'moo', bar: 'mog' }, { count: 2, foo: 'mop', bar: 'moo' },{ count: 2, foo: 'moo', bar: 'moo' }, { count: 3, foo: 'mop', bar: 'baz' }]
group.fields = ['foo', 'bar'];
comp.groupBys = [group];
comp.queryGroupByOptions = [[]];
comp.displaySankeyChart(group, 0);
expect(group.chart_type).toBe('sankey');
expect(group.chart_data.flowMax).toBe(13);
expect(group.chart_data.flowMax).toBe(15);
expect(group.chart_data.datasets[0].data).toStrictEqual([
{
"flow": 10,
"from": "mog",
"to": "mop",
},
{
"flow": 1,
"from": "moo",
Expand All @@ -426,6 +431,16 @@ test('displaySankeyChart', () => {
"from": "moo",
"to": "car",
},
{
"flow": 2,
"from": "moo",
"to": "mog",
},
{
"flow": 3,
"from": "mop",
"to": "baz",
},
]);
});

Expand Down

0 comments on commit 9cc88b6

Please sign in to comment.