chg: [internal] Optimise fetching trending tags widget

pull/6962/head
Jakub Onderka 2021-02-03 17:47:51 +01:00
parent 8ae1a1e1d4
commit a368e3196f
4 changed files with 80 additions and 69 deletions

View File

@ -1,6 +1,9 @@
<?php
App::uses('AppController', 'Controller');
/**
* @property Dashboard $Dashboard
*/
class DashboardsController extends AppController
{
public $components = array('Session', 'RequestHandler');
@ -147,47 +150,50 @@ class DashboardsController extends AppController
public function renderWidget($widget_id, $force = false)
{
if ($this->request->is('post')) {
if (empty($this->request->data['data'])) {
$this->request->data = array('data' => $this->request->data);
}
if (empty($this->request->data['data'])) {
throw new MethodNotAllowedException(__('You need to specify the widget to use along with the configuration.'));
}
$value = $this->request->data['data'];
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $value['widget']);
$this->layout = false;
$this->set('title', $dashboardWidget->title);
$redis = $this->Dashboard->setupRedis();
$org_scope = $this->_isSiteAdmin() ? 0 : $this->Auth->user('org_id');
$lookup_hash = hash('sha256', $value['widget'] . $value['config']);
$data = $redis->get('misp:dashboard:' . $org_scope . ':' . $lookup_hash);
if (!isset($dashboardWidget->cacheLifetime)) {
$dashboardWidget->cacheLifetime = false;
}
if (empty($dashboardWidget->cacheLifetime) || empty($data)) {
$data = $dashboardWidget->handler($this->Auth->user(), json_decode($value['config'], true));
if (!empty($dashboardWidget->cacheLifetime)) {
$redis->set('misp:dashboard:' . $org_scope . ':' . $lookup_hash, json_encode(array('data' => $data)));
$redis->expire('misp:dashboard:' . $org_scope . ':' . $lookup_hash, $dashboardWidget->cacheLifetime);
}
} else {
$data = json_decode($data, true)['data'];
}
$valueConfig = json_decode($value['config'], true);
$config = array(
'render' => $dashboardWidget->render,
'autoRefreshDelay' => empty($dashboardWidget->autoRefreshDelay) ? false : $dashboardWidget->autoRefreshDelay,
'widget_config' => empty($valueConfig['widget_config']) ? array() : $valueConfig['widget_config']
);
$this->set('widget_id', $widget_id);
$this->set('data', $data);
$this->set('config', $config);
$this->render('widget_loader');
} else {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException(__('This endpoint can only be reached via POST requests.'));
}
@session_write_close(); // allow concurrent AJAX requests (session hold lock by default)
if (empty($this->request->data['data'])) {
$this->request->data = array('data' => $this->request->data);
}
if (empty($this->request->data['data'])) {
throw new MethodNotAllowedException(__('You need to specify the widget to use along with the configuration.'));
}
$value = $this->request->data['data'];
$valueConfig = json_decode($value['config'], true);
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $value['widget']);
$redis = $this->Dashboard->setupRedis();
$org_scope = $this->_isSiteAdmin() ? 0 : $this->Auth->user('org_id');
$lookup_hash = hash('sha256', $value['widget'] . $value['config']);
$cacheKey = 'misp:dashboard:' . $org_scope . ':' . $lookup_hash;
$data = $redis->get($cacheKey);
if (!isset($dashboardWidget->cacheLifetime)) {
$dashboardWidget->cacheLifetime = false;
}
if (empty($dashboardWidget->cacheLifetime) || empty($data)) {
$data = $dashboardWidget->handler($this->Auth->user(), $valueConfig);
if (!empty($dashboardWidget->cacheLifetime)) {
$redis->setex($cacheKey, $dashboardWidget->cacheLifetime, json_encode(array('data' => $data)));
}
} else {
$data = json_decode($data, true)['data'];
}
$config = array(
'render' => $dashboardWidget->render,
'autoRefreshDelay' => empty($dashboardWidget->autoRefreshDelay) ? false : $dashboardWidget->autoRefreshDelay,
'widget_config' => empty($valueConfig['widget_config']) ? array() : $valueConfig['widget_config']
);
$this->layout = false;
$this->set('title', $dashboardWidget->title);
$this->set('widget_id', $widget_id);
$this->set('data', $data);
$this->set('config', $config);
$this->render('widget_loader');
}
public function import()

View File

@ -20,36 +20,41 @@ class TrendingTagsWidget
"include": ["misp-galaxy:", "my-internal-taxonomy"]
}';
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
public $cacheLifetime = 600;
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
$params = array(
'metadata' => 1,
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window'])
);
/** @var Event $eventModel */
$eventModel = ClassRegistry::init('Event');
$threshold = empty($options['threshold']) ? 10 : $options['threshold'];
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$events = array();
$params = [
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window']),
];
$eventIds = $eventModel->filterEventIds($user, $params);
$tags = [];
$tagColours = [];
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
}
$tags = array();
$tagColours = array();
foreach ($events as $event) {
foreach ($event['EventTag'] as $et) {
if ($this->checkTag($options, $et['Tag']['name'])) {
if (empty($tags[$et['Tag']['name']])) {
$tags[$et['Tag']['name']] = 1;
$tagColours[$et['Tag']['name']] = $et['Tag']['colour'];
} else {
$tags[$et['Tag']['name']] += 1;
}
$eventTags = $eventModel->EventTag->find('all', [
'conditions' => ['EventTag.event_id' => $eventIds],
'contain' => ['Tag' => ['fields' => ['name', 'colour']]],
'recursive' => -1,
'fields' => ['id'],
]);
foreach ($eventTags as $eventTag) {
$tagName = $eventTag['Tag']['name'];
if (isset($tags[$tagName])) {
$tags[$tagName]++;
} else if ($this->checkTag($options, $tagName)) {
$tags[$tagName] = 1;
$tagColours[$tagName] = $eventTag['Tag']['colour'];
}
}
arsort($tags);
}
arsort($tags);
$data['data'] = array_slice($tags, 0, $threshold);
$data['colours'] = $tagColours;
return $data;

View File

@ -8,7 +8,7 @@
?>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(function() {
if (<?= $config['autoRefreshDelay'] ? 'true' : 'false' ?>) {
setTimeout( function(){
updateDashboardWidget("#widget_<?= h($widget_id) ?>")},

View File

@ -5391,12 +5391,12 @@ function saveDashboardState() {
}
function updateDashboardWidget(element) {
element = $(element);
var $element = $(element);
if (element.length) {
var container_id = $(element).attr('id').substring(7);
var container = $(element).find('.widgetContent');
var titleText = $(element).find('.widgetTitleText');
var temp = JSON.parse($(element).attr('config'));
var container_id = $element.attr('id').substring(7);
var container = $element.find('.widgetContent');
var titleText = $element.find('.widgetTitleText');
var temp = JSON.parse($element.attr('config'));
if (temp['alias'] !== undefined) {
titleText.text(temp['alias']);
}
@ -5404,8 +5404,8 @@ function updateDashboardWidget(element) {
type: 'POST',
url: baseurl + '/dashboards/renderWidget/' + container_id,
data: {
config: $(element).attr('config'),
widget: $(element).attr('widget')
config: $element.attr('config'),
widget: $element.attr('widget')
},
success:function (data, textStatus) {
container.html(data);