mirror of https://github.com/MISP/MISP
new: [eventReport] Report from event
parent
c216642767
commit
e3d42ffe2a
|
@ -330,6 +330,45 @@ class EventReportsController extends AppController
|
|||
$this->render('ajax/importReportFromUrl');
|
||||
}
|
||||
|
||||
public function reportFromEvent($eventId)
|
||||
{
|
||||
$event = $this->__canModifyReport($eventId);
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$filters = $this->EventReport->jsonDecode($this->data['EventReport']['filters']);
|
||||
$options['conditions'] = $filters;
|
||||
$options['event_id'] = $eventId;
|
||||
App::uses('ReportFromEvent', 'EventReport');
|
||||
$optionFields = array_keys((new ReportFromEvent())->acceptedOptions);
|
||||
foreach ($optionFields as $field) {
|
||||
if (isset($this->data[$field])) {
|
||||
$options[$field] = $this->data[$field];
|
||||
}
|
||||
}
|
||||
$markdown = $this->EventReport->getReportFromEvent($this->Auth->user(), $options);
|
||||
if (!empty($markdown)) {
|
||||
$report = [
|
||||
'name' => __('Event report (%s)', time()),
|
||||
'distribution' => 5,
|
||||
'content' => $markdown
|
||||
];
|
||||
$errors = $this->EventReport->addReport($this->Auth->user(), $report, $eventId);
|
||||
} else {
|
||||
$errors[] = __('Could not generate markdown from the event');
|
||||
}
|
||||
$redirectTarget = array('controller' => 'events', 'action' => 'view', $eventId);
|
||||
if (!empty($errors)) {
|
||||
return $this->__getFailResponseBasedOnContext($errors, array(), 'add', $this->EventReport->id, $redirectTarget);
|
||||
} else {
|
||||
$successMessage = __('Report saved.');
|
||||
$report = $this->EventReport->simpleFetchById($this->Auth->user(), $this->EventReport->id);
|
||||
return $this->__getSuccessResponseBasedOnContext($successMessage, $report, 'add', false, $redirectTarget);
|
||||
}
|
||||
}
|
||||
$this->set('event_id', $eventId);
|
||||
$this->layout = 'ajax';
|
||||
$this->render('ajax/reportFromEvent');
|
||||
}
|
||||
|
||||
private function __generateIndexConditions($filters = [])
|
||||
{
|
||||
$aclConditions = $this->EventReport->buildACLConditions($this->Auth->user());
|
||||
|
|
|
@ -0,0 +1,162 @@
|
|||
<?php
|
||||
class ReportFromEvent
|
||||
{
|
||||
public $acceptedOptions = [
|
||||
'raw' => false, // if set to true, MISP elements will be put verbatim into the report instead of their reference
|
||||
'include_event_metadata' => true,
|
||||
'include_correlations' => true,
|
||||
'include_attack_matrix' => true,
|
||||
];
|
||||
|
||||
public function construct($eventModel, $user, $options)
|
||||
{
|
||||
$this->__eventModel = $eventModel;
|
||||
$this->__user = $user;
|
||||
$this->__options = array_merge($this->acceptedOptions, $options);
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getEvent()
|
||||
{
|
||||
$options = [
|
||||
'eventid' => $this->__options['event_id'],
|
||||
];
|
||||
$this->event = $this->__eventModel->fetchEvent($this->__user, $options);
|
||||
if (empty($this->event)) {
|
||||
throw new NotFoundException(__('Invalid event'));
|
||||
}
|
||||
$this->event = $this->event[0];
|
||||
$this->__eventModel->removeGalaxyClusterTags($this->event);
|
||||
}
|
||||
|
||||
public function generate()
|
||||
{
|
||||
$this->getEvent();
|
||||
$report = '';
|
||||
if ($this->__options['include_event_metadata']) {
|
||||
$report .= $this->getMarkdownForEventMetadata();
|
||||
}
|
||||
if ($this->__options['include_correlations']) {
|
||||
$report .= $this->mdHeader('4', __('Correlations'));
|
||||
$report .= $this->getMarkdownForEventCorrelations();
|
||||
}
|
||||
$report .= $this->mdHeader('3', __('Objects'));
|
||||
$report .= $this->getMarkdownForObjects();
|
||||
$report .= $this->mdHeader('3', __('Attributes'));
|
||||
$report .= $this->getMarkdownForAttributes();
|
||||
if ($this->__options['include_attack_matrix']) {
|
||||
$report .= $this->mdHeader('3', __('ATT&CK Matrix'));
|
||||
$report .= $this->getMarkdownForAttackMatrix();
|
||||
}
|
||||
return $report;
|
||||
}
|
||||
|
||||
private function getMarkdownForEventMetadata()
|
||||
{
|
||||
$markdown = $this->mdHeader('2', $this->event['Event']['info']);
|
||||
$markdown .= $this->mdList([
|
||||
__('Date') => $this->event['Event']['date'],
|
||||
__('Last update') => date('Y-m-d H:i:s', $this->event['Event']['timestamp']),
|
||||
__('Threat level') => $this->event['ThreatLevel']['name'],
|
||||
__('Attribute count') => $this->event['Event']['attribute_count'],
|
||||
], 'key');
|
||||
$markdown .= $this->mdHeader('4', __('Tags'));
|
||||
$markdown .= $this->getMarkdownForTags(Hash::extract($this->event['EventTag'], '{n}.Tag.name'));
|
||||
$markdown .= $this->mdHeader('4', __('Galaxies'));
|
||||
$markdown .= $this->getMarkdownForGalaxy($this->event['Galaxy']);
|
||||
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForTags($tags, $level=1)
|
||||
{
|
||||
if ($this->__options['raw']) {
|
||||
$markdown = $this->mdList($tags, false, $level);
|
||||
} else {
|
||||
$markdown = $this->mdList(array_map(function ($tag) {
|
||||
return sprintf('@[tag](%s)', $tag);
|
||||
}, $tags), false, $level);
|
||||
}
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForGalaxy($galaxies)
|
||||
{
|
||||
$markdown = '';
|
||||
foreach ($galaxies as $galaxy) {
|
||||
$markdown .= $this->mdList([
|
||||
__('Name') => $galaxy['name'],
|
||||
__('Description') => $galaxy['description'],
|
||||
], 'key');
|
||||
if ($this->__options['raw']) {
|
||||
foreach ($galaxy['GalaxyCluster'] as $cluster) {
|
||||
$markdown .= $this->mdList([
|
||||
__('Name') => $cluster['value'],
|
||||
__('Description') => $cluster['description'],
|
||||
], 'key', 2);
|
||||
}
|
||||
} else {
|
||||
$markdown .= $this->getMarkdownForTags(Hash::extract($galaxy['GalaxyCluster'], '{n}.tag_name'), 2);
|
||||
}
|
||||
}
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForObjects()
|
||||
{
|
||||
$markdown = $this->mdList(array_map(function ($uuid) {
|
||||
return sprintf('@[object](%s)', $uuid);
|
||||
}, Hash::extract($this->event['Object'], '{n}.uuid')), false);
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForAttributes()
|
||||
{
|
||||
$markdown = $this->mdList(array_map(function ($uuid) {
|
||||
return sprintf('@[attribute](%s)', $uuid);
|
||||
}, Hash::extract($this->event['Attribute'], '{n}.uuid')), false);
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForEventCorrelations()
|
||||
{
|
||||
$correlations = !empty($this->event['RelatedEvent']) ? $this->event['RelatedEvent'] : [];
|
||||
$markdown = $this->mdList(Hash::extract($correlations, '{n}.Event.info'), false, 2);
|
||||
return $markdown;
|
||||
}
|
||||
|
||||
private function getMarkdownForAttackMatrix()
|
||||
{
|
||||
return '@[galaxymatrix](c4e851fa-775f-11e7-8163-b774922098cd)';
|
||||
}
|
||||
|
||||
private function mdHeader($level, $content)
|
||||
{
|
||||
return str_repeat('#', $level) . ' ' . $content . PHP_EOL;
|
||||
}
|
||||
|
||||
private function mdTable($headers, $rows)
|
||||
{
|
||||
$table = '| ' . implode(' | ', $headers) . ' |' . PHP_EOL;
|
||||
$table .= '----------';
|
||||
foreach ($rows as $row) {
|
||||
$table = '| ' . implode(' | ', $row) . ' |' . PHP_EOL;
|
||||
}
|
||||
return $table;
|
||||
}
|
||||
|
||||
private function mdList($items, $prefix=false, $level=1)
|
||||
{
|
||||
$list = '';
|
||||
foreach ($items as $k => $item) {
|
||||
if ($prefix == 'index') {
|
||||
$list .= sprintf('%s%s. %s' . PHP_EOL, str_repeat(' ', $level), $k, $item);
|
||||
} elseif ($prefix == 'key') {
|
||||
$list .= sprintf('%s- *%s*: %s' . PHP_EOL, str_repeat(' ', $level), $k, $item);
|
||||
} else {
|
||||
$list .= sprintf('%s- %s' . PHP_EOL, str_repeat(' ', $level), $item);
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
}
|
|
@ -896,4 +896,13 @@ class EventReport extends AppModel
|
|||
$this->EventTag->attachTagToEvent($eventId, $tagId);
|
||||
}
|
||||
}
|
||||
|
||||
public function getReportFromEvent($user, $options)
|
||||
{
|
||||
App::uses('ReportFromEvent', 'EventReport');
|
||||
$reportGenerator = new ReportFromEvent();
|
||||
$reportGenerator->construct($this->Event, $user, $options);
|
||||
$report = $reportGenerator->generate();
|
||||
return $report;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,15 @@
|
|||
'fa-icon' => 'link',
|
||||
'requirement' => $canModify && $importModuleEnabled,
|
||||
),
|
||||
array(
|
||||
'onClick' => 'openGenericModal',
|
||||
'onClickParams' => [$baseurl . '/eventReports/reportFromEvent/' . h($event_id)],
|
||||
'active' => true,
|
||||
'text' => __('Generate report from Event'),
|
||||
'title' => __('Based on filters, create a report summarizing the event'),
|
||||
'fa-icon' => 'list-alt',
|
||||
'requirement' => $canModify,
|
||||
),
|
||||
)
|
||||
),
|
||||
array(
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
echo $this->element('genericElements/Form/genericForm', array(
|
||||
'form' => $this->Form,
|
||||
'data' => array(
|
||||
'title' => __('Create report from event', h($event_id)),
|
||||
'description' => __('Generate a report based on filtering criterias.'),
|
||||
'model' => 'EventReport',
|
||||
'fields' => array(
|
||||
array(
|
||||
'type' => 'textarea',
|
||||
'field' => 'filters',
|
||||
'class' => 'input span6',
|
||||
'div' => 'text',
|
||||
'label' => __('REST search filters'),
|
||||
'title' => __('Provide the filtering criterias for attributes to be taken into account in the report')
|
||||
),
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'field' => 'include_event_metadata',
|
||||
),
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'field' => 'include_correlations',
|
||||
),
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
'field' => 'include_attack_matrix',
|
||||
),
|
||||
),
|
||||
'submit' => array(
|
||||
'action' => $this->request->params['action'],
|
||||
'ajaxSubmit' => 'submitReportFromEvent()'
|
||||
)
|
||||
)
|
||||
));
|
||||
|
||||
echo $this->element('genericElements/assetLoader', array(
|
||||
'js' => array(
|
||||
'codemirror/codemirror',
|
||||
'codemirror/modes/javascript',
|
||||
'codemirror/addons/closebrackets',
|
||||
'codemirror/addons/lint',
|
||||
'codemirror/addons/jsonlint',
|
||||
'codemirror/addons/json-lint',
|
||||
),
|
||||
'css' => array(
|
||||
'codemirror',
|
||||
'codemirror/show-hint',
|
||||
'codemirror/lint',
|
||||
)
|
||||
));
|
||||
?>
|
||||
|
||||
<script>
|
||||
var cm
|
||||
function setupCodemirror() {
|
||||
var cmOptions = {
|
||||
mode: "application/json",
|
||||
theme:'default',
|
||||
gutters: ["CodeMirror-lint-markers"],
|
||||
lint: true,
|
||||
lineNumbers: true,
|
||||
indentUnit: 4,
|
||||
showCursorWhenSelecting: true,
|
||||
lineWrapping: true,
|
||||
autoCloseBrackets: true,
|
||||
}
|
||||
var defaultEditorContent = {
|
||||
value: '',
|
||||
type: '',
|
||||
category: '',
|
||||
tags: '',
|
||||
}
|
||||
cm = CodeMirror.fromTextArea(document.getElementById('EventReportFilters'), cmOptions);
|
||||
cm.setValue(JSON.stringify(defaultEditorContent, null, 4))
|
||||
}
|
||||
setTimeout(setupCodemirror, 350);
|
||||
|
||||
function submitReportFromEvent() {
|
||||
cm.save()
|
||||
submitPopoverForm('<?= h($event_id) ?>', 'addEventReport', 0, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.CodeMirror-wrap {
|
||||
border: 1px solid #cccccc;
|
||||
width: 500px;
|
||||
height: 150px;
|
||||
margin-bottom: 10px;
|
||||
resize: auto;
|
||||
}
|
||||
.cm-trailingspace {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom left;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.CodeMirror-gutters {
|
||||
z-index: 2;
|
||||
}
|
||||
</style>
|
Loading…
Reference in New Issue