mirror of https://github.com/MISP/MISP
chg: [user:periodic_notification] General improvements and added CLI support
parent
9d83f8a478
commit
7cd3b35d61
|
@ -578,6 +578,37 @@ class ServerShell extends AppShell
|
|||
$this->Task->saveField('message', count($servers) . ' job(s) completed at ' . date('d/m/Y - H:i:s') . '.');
|
||||
}
|
||||
|
||||
public function sendPeriodicSummaryToUsers()
|
||||
{
|
||||
$this->ConfigLoad->execute();
|
||||
$periods = $this->__getPeriodsForToday();
|
||||
$start_time = time();
|
||||
echo __n('Started periodic summary generation for the %s period', 'Started periodic summary generation for periods: %s', count($periods), implode(', ', $periods)) . PHP_EOL;
|
||||
foreach ($periods as $period) {
|
||||
$users = $this->User->getSubscribedUsersForPeriod($period);
|
||||
echo __n('%s user has subscribed for the `%s` period', '%s users has subscribed for the `%s` period', count($users), count($users), $period) . PHP_EOL;
|
||||
foreach ($users as $user) {
|
||||
echo __('Sending `%s` report to `%s`', $period, $user['User']['email']) . PHP_EOL;
|
||||
$emailTemplate = $this->User->generatePeriodicSummary($user['User']['id'], $period, false);
|
||||
$this->User->sendEmail($user, $emailTemplate, false, null);
|
||||
}
|
||||
}
|
||||
echo __('All reports sent. Task took %s secondes', time() - $start_time) . PHP_EOL;
|
||||
}
|
||||
|
||||
private function __getPeriodsForToday(): array
|
||||
{
|
||||
$today = new DateTime();
|
||||
$periods = ['daily'];
|
||||
if ($today->format('j') == 1) {
|
||||
$periods[] = 'weekly';
|
||||
}
|
||||
if ($today->format('N') == 1) {
|
||||
$periods[] = 'monthly';
|
||||
}
|
||||
return $periods;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @return array
|
||||
|
|
|
@ -471,6 +471,7 @@ class UsersController extends AppController
|
|||
} else {
|
||||
$this->set('urlparams', $urlParams);
|
||||
$this->set('passedArgsArray', $passedArgsArray);
|
||||
$this->set('periodic_notifications', $this->User::PERIODIC_NOTIFICATIONS);
|
||||
$conditions = array();
|
||||
if ($this->_isSiteAdmin()) {
|
||||
$users = $this->paginate();
|
||||
|
|
|
@ -1753,6 +1753,7 @@ class User extends AppModel
|
|||
$renderView = false;
|
||||
$filtersForRestSearch['publish_timestamp'] = $filtersForRestSearch['last'];
|
||||
$filtersForRestSearch['returnFormat'] = 'context';
|
||||
$filtersForRestSearch['staticHtml'] = true;
|
||||
unset($filtersForRestSearch['last']);
|
||||
$final = $this->Event->restSearch($user, 'context', $filtersForRestSearch, false, false, $elementCounter, $renderView);
|
||||
$final = json_decode($final->intoString(), true);
|
||||
|
@ -1763,6 +1764,8 @@ class User extends AppModel
|
|||
$emailTemplate->set('filters', $filters);
|
||||
$emailTemplate->set('period', $period);
|
||||
$emailTemplate->set('aggregated_context', $aggregated_context);
|
||||
$emailTemplate->set('analysisLevels', $this->Event->analysisLevels);
|
||||
$emailTemplate->set('distributionLevels', $this->Event->distributionLevels);
|
||||
if (!empty($rendered)) {
|
||||
$summary = $emailTemplate->render();
|
||||
return $summary->format() == 'text' ? $summary->text : $summary->html;
|
||||
|
@ -1818,7 +1821,6 @@ class User extends AppModel
|
|||
$timerange = '31d';
|
||||
}
|
||||
return $timerange;
|
||||
return $this->resolveTimeDelta($timerange);
|
||||
}
|
||||
|
||||
private function __getEventsForFilters(array $user, array $filters): array
|
||||
|
@ -1830,7 +1832,7 @@ class User extends AppModel
|
|||
|
||||
public function prepareEmailTemplate(string $period='daily'): SendEmailTemplate
|
||||
{
|
||||
$subject = sprintf('[%s MISP] %s %s', Configure::read('MISP.org'), Inflector::humanize($period), __('Notification'));
|
||||
$subject = sprintf('[%s MISP] %s %s', Configure::read('MISP.org'), Inflector::humanize($period), __('Notification - %s', (new DateTime())->format('Y-m-d')));
|
||||
$template = new SendEmailTemplate("notification_$period");
|
||||
$template->subject($subject);
|
||||
return $template;
|
||||
|
|
|
@ -110,11 +110,26 @@ foreach ($events as $event) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!function_exists('findAndBuildTag')) {
|
||||
function findAndBuildTag($tag_list, $tag_prefix, $that) {
|
||||
foreach ($tag_list as $tag) {
|
||||
if (substr($tag['Tag']['name'], 0, strlen($tag_prefix)) == $tag_prefix) {
|
||||
return $that->element('tag', ['tag' => $tag]);
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
$unique_tag_number = count(array_keys($all_tag_amount));
|
||||
|
||||
arsort($attribute_types);
|
||||
arsort($object_types);
|
||||
arsort($all_tag_amount);
|
||||
|
||||
array_splice($attribute_types, 10);
|
||||
array_splice($object_types, 10);
|
||||
array_splice($all_tag_amount, 10);
|
||||
?>
|
||||
|
||||
<h2><?= __('Summary of published Events') ?></h2>
|
||||
|
@ -171,39 +186,44 @@ arsort($all_tag_amount);
|
|||
<?php if ($this->fetch('detailed-summary-mitre-attack')): ?>
|
||||
<?= $this->fetch('detailed-summary-mitre-attack'); ?>
|
||||
<?php else: ?>
|
||||
<h4><img src="https://localhost:8443/img/mitre-attack-icon.ico" style="height: 1em; vertical-align: text-top;"> <?= __('Mitre Att&ck techniques') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($mitre_attack_techniques as $technique => $tag) : ?>
|
||||
<li>
|
||||
<?php
|
||||
$tag['Tag']['name'] = $technique;
|
||||
echo $this->element('tag', ['tag' => $tag])
|
||||
?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if (!empty($mitre_attack_techniques)): ?>
|
||||
<h4><?= __('Mitre Att&ck techniques') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($mitre_attack_techniques as $technique => $tag) : ?>
|
||||
<li>
|
||||
<?php
|
||||
$tag['Tag']['name'] = $technique;
|
||||
echo $this->element('tag', ['tag' => $tag])
|
||||
?>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($this->fetch('detailed-summary-type')): ?>
|
||||
<?= $this->fetch('detailed-summary-type'); ?>
|
||||
<?php else: ?>
|
||||
<h4><?= __('Entity type distribution') ?></h4>
|
||||
<h5><?= __('Attributes') ?></h5>
|
||||
<ul>
|
||||
<?php foreach ($attribute_types as $type => $amount) : ?>
|
||||
<li><strong><?= h($type) ?></strong>: <?= $amount ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if (!empty($attribute_types)): ?>
|
||||
<h4><?= __('Top 10 Attribute types') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($attribute_types as $type => $amount) : ?>
|
||||
<li><strong><?= h($type) ?></strong>: <?= $amount ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<h5><?= __('MISP Objects') ?></h5>
|
||||
<ul>
|
||||
<?php foreach ($object_types as $name => $amount) : ?>
|
||||
<li><strong><?= h($name) ?></strong>: <?= $amount ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php if (!empty($object_types)): ?>
|
||||
<h4><?= __('Top 10 MISP Object names') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($object_types as $name => $amount) : ?>
|
||||
<li><strong><?= h($name) ?></strong>: <?= $amount ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($all_event_report)): ?>
|
||||
<h5><?= __('Event Reports') ?></h5>
|
||||
<h4><?= __('All Event Reports') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($all_event_report as $report) : ?>
|
||||
<li>
|
||||
|
@ -219,7 +239,7 @@ arsort($all_tag_amount);
|
|||
<?php if ($this->fetch('detailed-summary-tags')): ?>
|
||||
<?= $this->fetch('detailed-summary-tags'); ?>
|
||||
<?php else: ?>
|
||||
<h4><?= __('Tags distribution') ?></h4>
|
||||
<h4><?= __('Top 10 Tags') ?></h4>
|
||||
<ul>
|
||||
<?php foreach ($all_tag_amount as $tag_name => $amount) : ?>
|
||||
<li>
|
||||
|
@ -235,17 +255,28 @@ arsort($all_tag_amount);
|
|||
<?php else: ?>
|
||||
<h3><?= __('Event list') ?></h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>TLP</th>
|
||||
<th>PAP</th>
|
||||
<th><?= __('State') ?></th>
|
||||
<th>ThreatLevel</th>
|
||||
<th><?= __('Event Info') ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($events as $event) : ?>
|
||||
<?php
|
||||
$tlpTag = array_filter($event['EventTag'], function ($event_tag) {
|
||||
return substr($event_tag['Tag']['name'], 0, 4) === 'tlp:';
|
||||
});
|
||||
$tlpTagHtml = !empty($tlpTag) ? $this->element('tag', ['tag' => $tlpTag[0]]) : '';
|
||||
?>
|
||||
<?php
|
||||
$workflowTag = findAndBuildTag($event['EventTag'], 'workflow:', $this);
|
||||
$analysisHtml = !empty($workflowTag) ? $workflowTag : h($analysisLevels[$event['Event']['analysis']]);
|
||||
$tlpTag = findAndBuildTag($event['EventTag'], 'tlp:', $this);
|
||||
$tlpHtml = !empty($tlpTag) ? $tlpTag : h($distributionLevels[$event['Event']['distribution']]);
|
||||
?>
|
||||
<tr>
|
||||
<td><?= $tlpTagHtml ?></td>
|
||||
<td>[<?= h($event['ThreatLevel']['name']); ?>]</td>
|
||||
<td><?= $tlpHtml ?></td>
|
||||
<td><?= findAndBuildTag($event['EventTag'], 'PAP:', $this) ?></td>
|
||||
<td><?= $analysisHtml ?></td>
|
||||
<td><?= h($event['ThreatLevel']['name']); ?></td>
|
||||
<td><a href="<?= sprintf('%s/events/view/%s', $baseurl, h($event['Event']['uuid'])) ?>"><?= h($event['Event']['info']); ?></a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
|
|
@ -154,6 +154,20 @@
|
|||
'data_path' => 'User.contactalert',
|
||||
'colors' => true,
|
||||
),
|
||||
array(
|
||||
'name' => __('Periodic notif.'),
|
||||
'element' => 'custom',
|
||||
'class' => 'short',
|
||||
'function' => function (array $user) use ($periodic_notifications) {
|
||||
$period_subscriptions = [];
|
||||
foreach ($periodic_notifications as $period) {
|
||||
if (!empty($user['User'][$period])) {
|
||||
$period_subscriptions[] = substr($period, 13, 1);
|
||||
}
|
||||
}
|
||||
return implode('/', $period_subscriptions);
|
||||
}
|
||||
),
|
||||
array(
|
||||
'name' => __('PGP Key'),
|
||||
'element' => 'boolean',
|
||||
|
|
|
@ -17,7 +17,7 @@ echo $this->element('genericElements/Form/genericForm', [
|
|||
],
|
||||
[
|
||||
'field' => 'notification_monthly',
|
||||
'label' => __('Subscribe to montly notifications'),
|
||||
'label' => __('Subscribe to monthly notifications'),
|
||||
'default' => 0,
|
||||
'type' => 'checkbox'
|
||||
],
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div class="btn-group">
|
||||
<a class="btn <?= $period == 'daily' ? 'btn-primary' : 'btn-inverse' ?>" href="<?= $baseurl . '/users/viewPeriodicSummary/daily' ?>"><?= __('Daily') ?></a>
|
||||
<a class="btn <?= $period == 'weekly' ? 'btn-primary' : 'btn-inverse' ?>" href="<?= $baseurl . '/users/viewPeriodicSummary/weekly' ?>"><?= __('Weekly') ?></a>
|
||||
<a class="btn <?= $period == 'monthly' ? 'btn-primary' : 'btn-inverse' ?>" href="<?= $baseurl . '/users/viewPeriodicSummary/monthly' ?>"><?= __('Montly') ?></a>
|
||||
<a class="btn <?= $period == 'monthly' ? 'btn-primary' : 'btn-inverse' ?>" href="<?= $baseurl . '/users/viewPeriodicSummary/monthly' ?>"><?= __('Monthly') ?></a>
|
||||
</div>
|
||||
|
||||
<h2><?= __('MISP %s summary', h($period)); ?></h2>
|
||||
|
|
Loading…
Reference in New Issue