mirror of https://github.com/MISP/MISP
Merge branch 'new_widgets' into develop
commit
9f5e49995a
|
@ -417,9 +417,12 @@ class AppController extends Controller
|
|||
}
|
||||
}
|
||||
if ($foundMispAuthKey) {
|
||||
$authKeyToStore = substr($authKey, 0, 4)
|
||||
$start = substr($authKey, 0, 4);
|
||||
$end = substr($authKey, -4);
|
||||
$authKeyToStore = $start
|
||||
. str_repeat('*', 32)
|
||||
. substr($authKey, -4);
|
||||
. $end;
|
||||
$this->__logApiKeyUse($start . $end);
|
||||
if ($user) {
|
||||
// User found in the db, add the user info to the session
|
||||
if (Configure::read('MISP.log_auth')) {
|
||||
|
@ -642,6 +645,15 @@ class AppController extends Controller
|
|||
return in_array($this->request->params['action'], $actionsToCheck[$controller], true);
|
||||
}
|
||||
|
||||
private function __logApiKeyUse($apikey)
|
||||
{
|
||||
$redis = $this->User->setupRedis();
|
||||
if (!$redis) {
|
||||
return;
|
||||
}
|
||||
$redis->zIncrBy('misp:authkey_log:' . date("Ymd"), 1, $apikey);
|
||||
}
|
||||
|
||||
/**
|
||||
* User access monitoring
|
||||
* @param array $user
|
||||
|
|
|
@ -316,6 +316,8 @@ class DashboardsController extends AppController
|
|||
public function listTemplates()
|
||||
{
|
||||
$conditions = array();
|
||||
// load all widgets for internal use, won't be displayed to the user. Thus we circumvent the ACL on it.
|
||||
$accessible_widgets = array_keys($this->Dashboard->loadAllWidgets($this->Auth->user()));
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$permission_flags = array();
|
||||
foreach ($this->Auth->user('Role') as $perm => $value) {
|
||||
|
@ -394,6 +396,15 @@ class DashboardsController extends AppController
|
|||
}
|
||||
$element['Dashboard']['widgets'] = array_keys($widgets);
|
||||
sort($element['Dashboard']['widgets']);
|
||||
$temp = [];
|
||||
foreach ($element['Dashboard']['widgets'] as $widget) {
|
||||
if (in_array($widget, $accessible_widgets)) {
|
||||
$temp['allow'][] = $widget;
|
||||
} else {
|
||||
$temp['deny'][] = $widget;
|
||||
}
|
||||
}
|
||||
$element['Dashboard']['widgets'] = $temp;
|
||||
if ($element['Dashboard']['user_id'] != $this->Auth->user('id')) {
|
||||
$element['User']['email'] = '';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
<?php
|
||||
|
||||
class APIActivityWidget
|
||||
{
|
||||
public $title = 'API Activity';
|
||||
public $render = 'SimpleList';
|
||||
public $width = 2;
|
||||
public $height = 2;
|
||||
public $params = [
|
||||
'filter' => 'A list of filters by organisation meta information (sector, type, nationality, id, uuid) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'limit' => 'Limits the number of displayed APIkeys. (-1 will list all) Default: -1',
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show contributions in the past 7 days. (integer)',
|
||||
'month' => 'Who contributed most this month? (boolean)',
|
||||
'year' => 'Which contributed most this year? (boolean)',
|
||||
];
|
||||
public $description = 'Basic widget showing some server statistics in regards to MISP.';
|
||||
public $cacheLifetime = 10;
|
||||
public $autoRefreshDelay = null;
|
||||
private $User = null;
|
||||
private $AuthKey = null;
|
||||
|
||||
|
||||
private function getDates($options)
|
||||
{
|
||||
if (!empty($options['days'])) {
|
||||
$begin = new DateTime(date('Y-m-d', strtotime(sprintf("-%s days", $options['days']))));
|
||||
} else if (!empty($options['month'])) {
|
||||
$begin = new DateTime(date('Y-m-d', strtotime('first day of this month 00:00:00', time())));
|
||||
} else if (!empty($options['year'])) {
|
||||
$begin = new DateTime(date('Y-m-d', strtotime('first day of this year 00:00:00', time())));
|
||||
} else {
|
||||
$begin = new DateTime(date('Y-m-d', strtotime('-7 days', time())));;
|
||||
}
|
||||
$now = new DateTime();
|
||||
$dates = new DatePeriod(
|
||||
$begin,
|
||||
new DateInterval('P1D'),
|
||||
$now
|
||||
);
|
||||
$results = [];
|
||||
foreach ($dates as $date) {
|
||||
$results[] = $date->format('Ymd');
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
$this->AuthKey = ClassRegistry::init('AuthKey');
|
||||
$redis = $this->User->setupRedis();
|
||||
if (!$redis) {
|
||||
throw new NotFoundException(__('No redis connection found.'));
|
||||
}
|
||||
|
||||
$params = ['conditions' => []];
|
||||
$dates = $this->getDates($options);
|
||||
$pipe = $redis->pipeline();
|
||||
foreach ($dates as $date) {
|
||||
$pipe->zrange('misp:authkey_log:' . $date, 0, -1, true);
|
||||
}
|
||||
$temp = $pipe->exec();
|
||||
$raw_results = [];
|
||||
$counts = [];
|
||||
foreach ($dates as $k => $date) {
|
||||
$raw_results[$date] = $temp[$k];
|
||||
if (!empty($temp[$k])) {
|
||||
foreach ($temp[$k] as $key => $count) {
|
||||
if (isset($counts[$key])) {
|
||||
$counts[$key] += (int)$count;
|
||||
} else {
|
||||
$counts[$key] = (int)$count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
arsort($counts);
|
||||
$this->AuthKey->Behaviors->load('Containable');
|
||||
$temp_apikeys = array_flip(array_keys($counts));
|
||||
foreach ($temp_apikeys as $apikey => $value) {
|
||||
$temp_apikeys[$apikey] = $this->AuthKey->find('first', [
|
||||
'conditions' => [
|
||||
'AuthKey.authkey_start' => substr($apikey, 0, 4),
|
||||
'AuthKey.authkey_end' => substr($apikey, 4)
|
||||
],
|
||||
'fields' => ['AuthKey.authkey_start', 'AuthKey.authkey_end', 'AuthKey.id', 'User.id', 'User.email'],
|
||||
'recursive' => 1
|
||||
]);
|
||||
}
|
||||
$baseurl = empty(Configure::read('MISP.external_baseurl')) ? h(Configure::read('MISP.baseurl')) : Configure::read('MISP.external_baseurl');
|
||||
foreach ($counts as $key => $junk) {
|
||||
$data = $temp_apikeys[$key];
|
||||
if (!empty($data)) {
|
||||
$results[] = [
|
||||
'html_title' => sprintf(
|
||||
'<a href="%s/auth_keys/view/%s">%s</a>',
|
||||
h($baseurl),
|
||||
h($data['AuthKey']['id']),
|
||||
$key
|
||||
),
|
||||
'html' => sprintf(
|
||||
'%s (<a href="%s/admin/users/view/%s">%s</a>)',
|
||||
h($counts[$key]),
|
||||
h($baseurl),
|
||||
h($data['User']['id']),
|
||||
h($data['User']['email'])
|
||||
)
|
||||
];
|
||||
} else {
|
||||
$results[] = [
|
||||
'title' => $key,
|
||||
'html' => sprintf(
|
||||
'%s (<span class="red" title="%s">%s</span>)',
|
||||
h($counts[$key]),
|
||||
__('An unknown key can be caused by the given key having been permanently deleted or falsely mis-identified (for the purposes of this widget) on instances using legacy API key authentication.'),
|
||||
__('Unknown key')
|
||||
)
|
||||
];
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function checkPermissions($user)
|
||||
{
|
||||
if (empty($user['Role']['perm_site_admin'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
<?php
|
||||
|
||||
class LoginsWidget
|
||||
{
|
||||
public $title = 'Logins';
|
||||
public $render = 'SimpleList';
|
||||
public $width = 2;
|
||||
public $height = 2;
|
||||
public $params = [
|
||||
'filter' => 'A list of filters by organisation meta information (sector, type, nationality, id, uuid) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'limit' => 'Limits the number of displayed APIkeys. (-1 will list all) Default: -1',
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show contributions in the past 7 days. (integer)',
|
||||
'month' => 'Who contributed most this month? (boolean)',
|
||||
'year' => 'Which contributed most this year? (boolean)',
|
||||
];
|
||||
public $description = 'Basic widget showing some server statistics in regards to MISP.';
|
||||
public $cacheLifetime = 10;
|
||||
public $autoRefreshDelay = null;
|
||||
private $User = null;
|
||||
private $Log = null;
|
||||
|
||||
|
||||
private function getDates($options)
|
||||
{
|
||||
if (!empty($options['days'])) {
|
||||
$begin = date('Y-m-d H:i:s', strtotime(sprintf("-%s days", $options['days'])));
|
||||
} else if (!empty($options['month'])) {
|
||||
$begin = date('Y-m-d H:i:s', strtotime('first day of this month 00:00:00', time()));
|
||||
} else if (!empty($options['year'])) {
|
||||
$begin = date('Y-m-d', strtotime('first day of this year 00:00:00', time()));
|
||||
} else {
|
||||
$begin = date('Y-m-d H:i:s', strtotime('-7 days', time()));
|
||||
}
|
||||
return $begin ? ['Log.created >=' => $begin] : [];
|
||||
}
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$conditions = $this->getDates($options);
|
||||
$conditions['Log.action'] = 'login';
|
||||
$this->Log->Behaviors->load('Containable');
|
||||
$this->Log->bindModel([
|
||||
'belongsTo' => [
|
||||
'User'
|
||||
]
|
||||
]);
|
||||
$this->Log->virtualFields['count'] = 0;
|
||||
$this->Log->virtualFields['email'] = '';
|
||||
$logs = $this->Log->find('all', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['Log.user_id', 'COUNT(Log.id) AS Log__count', 'User.email AS Log__email'],
|
||||
'contain' => ['User'],
|
||||
'group' => ['Log.user_id']
|
||||
]);
|
||||
$counts = [];
|
||||
$emails = [];
|
||||
foreach ($logs as $log) {
|
||||
$counts[$log['Log']['user_id']] = $log['Log']['count'];
|
||||
$emails[$log['Log']['user_id']] = $log['Log']['email'];
|
||||
}
|
||||
$results = [];
|
||||
arsort($counts);
|
||||
$baseurl = empty(Configure::read('MISP.external_baseurl')) ? h(Configure::read('MISP.baseurl')) : Configure::read('MISP.external_baseurl');
|
||||
foreach ($counts as $user_id => $count) {
|
||||
$results[] = [
|
||||
'html_title' => sprintf(
|
||||
'<a href="%s/admin/users/view/%s">%s</a>',
|
||||
h($baseurl),
|
||||
h($user_id),
|
||||
h($emails[$user_id])
|
||||
),
|
||||
'value' => $count
|
||||
];
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
public function checkPermissions($user)
|
||||
{
|
||||
if (empty($user['Role']['perm_site_admin'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
<?php
|
||||
|
||||
class NewOrgsWidget
|
||||
{
|
||||
public $title = 'New organisations';
|
||||
public $render = 'Index';
|
||||
public $width = 7;
|
||||
public $height = 6;
|
||||
public $description = 'A list of the latest new member organisations.';
|
||||
private $tableDescription = null;
|
||||
public $cacheLifetime = null;
|
||||
public $autoRefreshDelay = false;
|
||||
public $params = [
|
||||
'limit' => 'Maximum number of joining organisations shown. (integer, defaults to 10 if not set)',
|
||||
'filter' => 'A list of filters by organisation meta information (nationality, sector, type, name, uuid) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show the organisations that were added in the past 7 days. (integer)',
|
||||
'month' => 'Which organisations have been added this month? (boolean)',
|
||||
'year' => 'Which organisations have been added this year? (boolean)',
|
||||
'local' => 'Should the list only show local organisations? (boolean or list of booleans, defaults to 1. To get both sets, use [0,1])',
|
||||
'fields' => 'Which fields should be displayed, by default all are selected. Pass a list with the following options: [id, uuid, name, sector, type, nationality, creation_date]'
|
||||
];
|
||||
private $validFilterKeys = [
|
||||
'nationality',
|
||||
'sector',
|
||||
'type',
|
||||
'name',
|
||||
'uuid'
|
||||
];
|
||||
|
||||
public $placeholder =
|
||||
'{
|
||||
"limit": 5,
|
||||
"filter": {
|
||||
"nationality": [
|
||||
"Hungary",
|
||||
"Russia",
|
||||
"North Korea"
|
||||
]
|
||||
},
|
||||
"month": true
|
||||
}';
|
||||
|
||||
private $Organisation = null;
|
||||
|
||||
private function timeConditions($options)
|
||||
{
|
||||
$limit = empty($options['limit']) ? 10 : $options['limit'];
|
||||
if (!empty($options['days'])) {
|
||||
$condition = strtotime(sprintf("-%s days", $options['days']));
|
||||
$this->tableDescription = __('The %d newest organisations created in the past %d days', $limit, (int)$options['days']);
|
||||
} else if (!empty($options['month'])) {
|
||||
$condition = strtotime('first day of this month 00:00:00', time());
|
||||
$this->tableDescription = __('The %d newest organisations created during the current month', $limit);
|
||||
} else if (!empty($options['year'])) {
|
||||
$condition = strtotime('first day of this year 00:00:00', time());
|
||||
$this->tableDescription = __('The %d newest organisations created during the current year', $limit);
|
||||
} else {
|
||||
$this->tableDescription = __('The %d newest organisations created', $limit);
|
||||
return null;
|
||||
}
|
||||
$datetime = new DateTime();
|
||||
$datetime->setTimestamp($condition);
|
||||
return $datetime->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->Organisation = ClassRegistry::init('Organisation');
|
||||
$field_options = [
|
||||
'id' => [
|
||||
'name' => '#',
|
||||
'url' => Configure::read('MISP.baseurl') . '/organisations/view',
|
||||
'element' => 'links',
|
||||
'data_path' => 'Organisation.id',
|
||||
'url_params_data_paths' => 'Organisation.id'
|
||||
],
|
||||
'date_created' => [
|
||||
'name' => 'Creation date',
|
||||
'data_path' => 'Organisation.date_created'
|
||||
],
|
||||
'name' => [
|
||||
'name' => 'Name',
|
||||
'data_path' => 'Organisation.name',
|
||||
],
|
||||
'uuid' => [
|
||||
'name' => 'UUID',
|
||||
'data_path' => 'Organisation.uuid',
|
||||
],
|
||||
'sector' => [
|
||||
'name' => 'Sector',
|
||||
'data_path' => 'Organisation.sector',
|
||||
],
|
||||
'nationality' => [
|
||||
'name' => 'Nationality',
|
||||
'data_path' => 'Organisation.nationality',
|
||||
],
|
||||
'type' => [
|
||||
'name' => 'Type',
|
||||
'data_path' => 'Organisation.type',
|
||||
]
|
||||
];
|
||||
$params = [
|
||||
'conditions' => [
|
||||
'AND' => ['Organisation.local' => !isset($options['local']) ? 1 : $options['local']]
|
||||
],
|
||||
'limit' => 10,
|
||||
'recursive' => -1
|
||||
];
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$params['conditions']['AND'][] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$timeConditions = $this->timeConditions($options);
|
||||
if ($timeConditions) {
|
||||
$params['conditions']['AND'][] = ['Organisation.date_created >=' => $timeConditions];
|
||||
}
|
||||
if (isset($options['fields'])) {
|
||||
$fields = [];
|
||||
foreach ($options['fields'] as $field) {
|
||||
if (isset($field_options[$field])) {
|
||||
$fields[$field] = $field_options[$field];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fields = $field_options;
|
||||
}
|
||||
$data = $this->Organisation->find('all', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $params['conditions'],
|
||||
'limit' => isset($options['limit']) ? (int)$options['limit'] : 10,
|
||||
'fields' => array_keys($fields),
|
||||
'order' => 'Organisation.date_created DESC'
|
||||
]);
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'fields' => $fields,
|
||||
'description' => $this->tableDescription
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,171 @@
|
|||
<?php
|
||||
|
||||
class NewUsersWidget
|
||||
{
|
||||
public $title = 'New users';
|
||||
public $render = 'Index';
|
||||
public $width = 7;
|
||||
public $height = 6;
|
||||
public $description = 'A list of the latest new users.';
|
||||
private $tableDescription = null;
|
||||
public $cacheLifetime = null;
|
||||
public $autoRefreshDelay = false;
|
||||
public $params = [
|
||||
'limit' => 'Maximum number of joining users shown. (integer, defaults to 10 if not set)',
|
||||
'filter' => 'A list of filters for the organisations (nationality, sector, type, name, uuid) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show the organisations that were added in the past 7 days. (integer)',
|
||||
'month' => 'Which organisations have been added this month? (boolean)',
|
||||
'year' => 'Which organisations have been added this year? (boolean)',
|
||||
'fields' => 'Which fields should be displayed, by default all are selected. Pass a list with the following options: [id, email, Organisation.name, Role.name, date_created]'
|
||||
];
|
||||
private $validFilterKeys = [
|
||||
'id',
|
||||
'email',
|
||||
'Organisation.name',
|
||||
'Role.name',
|
||||
'date_created'
|
||||
];
|
||||
|
||||
public $placeholder =
|
||||
'{
|
||||
"limit": 10,
|
||||
"filter": {
|
||||
"Organisation.name": [
|
||||
"!FSB",
|
||||
"!GRU",
|
||||
"!Kaspersky"
|
||||
],
|
||||
"email": [
|
||||
"!andras.iklody@circl.lu"
|
||||
],
|
||||
"Role.name": [
|
||||
"Publisher",
|
||||
"User"
|
||||
]
|
||||
},
|
||||
"year": true
|
||||
}';
|
||||
|
||||
private $User = null;
|
||||
|
||||
private function timeConditions($options)
|
||||
{
|
||||
$limit = empty($options['limit']) ? 10 : $options['limit'];
|
||||
if (!empty($options['days'])) {
|
||||
$condition = strtotime(sprintf("-%s days", $options['days']));
|
||||
$this->tableDescription = __('The %d newest users created in the past %d days', $limit, (int)$options['days']);
|
||||
} else if (!empty($options['month'])) {
|
||||
$condition = strtotime('first day of this month 00:00:00', time());
|
||||
$this->tableDescription = __('The %d newest users created during the current month', $limit);
|
||||
} else if (!empty($options['year'])) {
|
||||
$condition = strtotime('first day of this year 00:00:00', time());
|
||||
$this->tableDescription = __('The %d newest users created during the current year', $limit);
|
||||
} else {
|
||||
$this->tableDescription = __('The %d newest users created', $limit);
|
||||
return null;
|
||||
}
|
||||
return $condition;
|
||||
}
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$this->User = ClassRegistry::init('User');
|
||||
$field_options = [
|
||||
'id' => [
|
||||
'name' => '#',
|
||||
'url' => empty($user['Role']['perm_site_admin']) ? null : Configure::read('MISP.baseurl') . '/admin/users/view',
|
||||
'element' => 'links',
|
||||
'data_path' => 'User.id',
|
||||
'url_params_data_paths' => 'User.id'
|
||||
],
|
||||
'date_created' => [
|
||||
'name' => 'Creation date',
|
||||
'data_path' => 'User.date_created'
|
||||
],
|
||||
'email' => [
|
||||
'name' => 'E-mail',
|
||||
'data_path' => 'User.email',
|
||||
],
|
||||
'Organisation.name' => [
|
||||
'name' => 'Organisation',
|
||||
'data_path' => 'Organisation.name',
|
||||
],
|
||||
'Role.name' => [
|
||||
'name' => 'Role',
|
||||
'data_path' => 'Role.name',
|
||||
]
|
||||
];
|
||||
$params = [
|
||||
'conditions' => [],
|
||||
'limit' => 10,
|
||||
'recursive' => -1
|
||||
];
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
$filterName = strpos($filterKey, '.') ? $filterKey : 'User.' . $filterKey;
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket[$filterName . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket[$filterName . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$params['conditions']['AND'][] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$timeConditions = $this->timeConditions($options);
|
||||
if ($timeConditions) {
|
||||
$params['conditions']['AND'][] = ['User.date_created >=' => $timeConditions];
|
||||
}
|
||||
if (isset($options['fields'])) {
|
||||
$fields = [];
|
||||
foreach ($options['fields'] as $field) {
|
||||
if (isset($field_options[$field])) {
|
||||
$fields[$field] = $field_options[$field];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$fields = $field_options;
|
||||
}
|
||||
|
||||
// redact e-mails for non site admins unless specifically allowed
|
||||
if (
|
||||
empty($user['Role']['perm_site_admin']) &&
|
||||
!Configure::read('Security.disclose_user_emails') &&
|
||||
isset($fields['email'])
|
||||
) {
|
||||
unset($fields['email']);
|
||||
}
|
||||
$data = $this->User->find('all', [
|
||||
'recursive' => -1,
|
||||
'contain' => ['Organisation.name', 'Role.name'],
|
||||
'conditions' => $params['conditions'],
|
||||
'limit' => isset($options['limit']) ? $options['limit'] : 10,
|
||||
'fields' => array_keys($fields),
|
||||
'order' => 'User.date_created DESC'
|
||||
]);
|
||||
|
||||
foreach ($data as &$u) {
|
||||
if (empty($u['User']['date_created'])) {
|
||||
continue;
|
||||
}
|
||||
$tempDate = new DateTime();
|
||||
$tempDate->setTimestamp($u['User']['date_created']);
|
||||
$u['User']['date_created'] = $tempDate->format('Y-m-d H:i:s');
|
||||
}
|
||||
|
||||
return [
|
||||
'data' => $data,
|
||||
'fields' => $fields,
|
||||
'description' => $this->tableDescription
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
<?php
|
||||
class OrgContributionToplistWidget
|
||||
{
|
||||
public $title = 'Contributor Top List (Orgs)';
|
||||
public $render = 'BarChart';
|
||||
public $description = 'The top contributors (orgs) in a selected time frame.';
|
||||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = [
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show contributions in the past 7 days. (integer)',
|
||||
'month' => 'Who contributed most this month? (boolean)',
|
||||
'year' => 'Which contributed most this year? (boolean)',
|
||||
'filter' => 'A list of filters by organisation meta information (nationality, sector, type, name, uuid, local (- expects a boolean or a list of boolean values)) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'limit' => 'Limits the number of displayed tags. Default: 10'
|
||||
];
|
||||
public $cacheLifetime = null;
|
||||
public $autoRefreshDelay = false;
|
||||
private $validFilterKeys = [
|
||||
'nationality',
|
||||
'sector',
|
||||
'type',
|
||||
'name',
|
||||
'uuid'
|
||||
];
|
||||
public $placeholder =
|
||||
'{
|
||||
"days": "7d",
|
||||
"threshold": 15,
|
||||
"filter": {
|
||||
"sector": "Financial"
|
||||
}
|
||||
}';
|
||||
private $Org = null;
|
||||
private $Event = null;
|
||||
|
||||
|
||||
private function timeConditions($options)
|
||||
{
|
||||
$limit = empty($options['limit']) ? 10 : $options['limit'];
|
||||
if (!empty($options['days'])) {
|
||||
$condition = strtotime(sprintf("-%s days", $options['days']));
|
||||
} else if (!empty($options['month'])) {
|
||||
$condition = strtotime('first day of this month 00:00:00', time());
|
||||
} else if (!empty($options['year'])) {
|
||||
$condition = strtotime('first day of this year 00:00:00', time());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return $condition;
|
||||
}
|
||||
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$params = ['conditions' => []];
|
||||
$timeConditions = $this->timeConditions($options);
|
||||
if ($timeConditions) {
|
||||
$params['conditions']['AND'][] = ['Event.timestamp >=' => $timeConditions];
|
||||
}
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$params['conditions']['AND'][] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($options['filter']['local'])) {
|
||||
$params['conditions']['AND']['local'] = $options['filter']['local'];
|
||||
}
|
||||
|
||||
$this->Org = ClassRegistry::init('Organisation');
|
||||
$org_ids = $this->Org->find('list', [
|
||||
'fields' => ['Organisation.id', 'Organisation.name'],
|
||||
'conditions' => $params['conditions']
|
||||
]);
|
||||
$conditions = ['Event.orgc_id IN' => array_keys($org_ids)];
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$this->Event->virtualFields['frequency'] = 0;
|
||||
$orgs = $this->Event->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['orgc_id', 'count(Event.orgc_id) as Event__frequency'],
|
||||
'group' => ['orgc_id'],
|
||||
'conditions' => $conditions,
|
||||
'order' => 'count(Event.orgc_id) desc',
|
||||
'limit' => empty($options['limit']) ? 10 : $options['limit']
|
||||
]);
|
||||
$results = [];
|
||||
foreach($orgs as $org) {
|
||||
$results[$org_ids[$org['Event']['orgc_id']]] = $org['Event']['frequency'];
|
||||
}
|
||||
return ['data' => $results];
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,250 @@
|
|||
<?php
|
||||
class OrganisationMapWidget
|
||||
{
|
||||
public $title = 'Organisation world map';
|
||||
public $render = 'WorldMap';
|
||||
public $description = 'The countries represented via organisations on the current instance.';
|
||||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = [
|
||||
'filter' => 'A list of filters by organisation meta information (sector, type, local (- expects a boolean or a list of boolean values)) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'limit' => 'Limits the number of displayed tags. Default: 10'
|
||||
];
|
||||
public $cacheLifetime = null;
|
||||
public $autoRefreshDelay = false;
|
||||
private $validFilterKeys = [
|
||||
'sector',
|
||||
'type',
|
||||
'local'
|
||||
];
|
||||
public $placeholder =
|
||||
'{
|
||||
"type": "Member",
|
||||
"local": [0,1]
|
||||
}';
|
||||
private $Organisation = null;
|
||||
|
||||
public $countryCodes = array(
|
||||
'Afghanistan' => 'AF',
|
||||
'Albania' => 'AL',
|
||||
'Algeria' => 'DZ',
|
||||
'Angola' => 'AO',
|
||||
'Argentina' => 'AR',
|
||||
'Armenia' => 'AM',
|
||||
'Australia' => 'AU',
|
||||
'Austria' => 'AT',
|
||||
'Azerbaijan' => 'AZ',
|
||||
'Bahamas' => 'BS',
|
||||
'Bangladesh' => 'BD',
|
||||
'Belarus' => 'BY',
|
||||
'Belgium' => 'BE',
|
||||
'Belize' => 'BZ',
|
||||
'Benin' => 'BJ',
|
||||
'Bhutan' => 'BT',
|
||||
'Bolivia' => 'BO',
|
||||
'Bosnia and Herz.' => 'BA',
|
||||
'Botswana' => 'BW',
|
||||
'Brazil' => 'BR',
|
||||
'Brunei' => 'BN',
|
||||
'Bulgaria' => 'BG',
|
||||
'Burkina Faso' => 'BF',
|
||||
'Burundi' => 'BI',
|
||||
'Cambodia' => 'KH',
|
||||
'Cameroon' => 'CM',
|
||||
'Canada' => 'CA',
|
||||
'Central African Rep.' => 'CF',
|
||||
'Chad' => 'TD',
|
||||
'Chile' => 'CL',
|
||||
'China' => 'CN',
|
||||
'Colombia' => 'CO',
|
||||
'Congo' => 'CG',
|
||||
'Costa Rica' => 'CR',
|
||||
'Croatia' => 'HR',
|
||||
'Cuba' => 'CU',
|
||||
'Cyprus' => 'CY',
|
||||
'Czech Rep.' => 'CZ',
|
||||
'Côte d\'Ivoire' => 'CI',
|
||||
'Dem. Rep. Congo' => 'CD',
|
||||
'Dem. Rep. Korea' => 'KP',
|
||||
'Denmark' => 'DK',
|
||||
'Djibouti' => 'DJ',
|
||||
'Dominican Rep.' => 'DO',
|
||||
'Ecuador' => 'EC',
|
||||
'Egypt' => 'EG',
|
||||
'El Salvador' => 'SV',
|
||||
'Eq. Guinea' => 'GQ',
|
||||
'Eritrea' => 'ER',
|
||||
'Estonia' => 'EE',
|
||||
'Ethiopia' => 'ET',
|
||||
'Falkland Is.' => 'FK',
|
||||
'Fiji' => 'FJ',
|
||||
'Finland' => 'FI',
|
||||
'Fr. S. Antarctic Lands' => 'TF',
|
||||
'France' => 'FR',
|
||||
'Gabon' => 'GA',
|
||||
'Gambia' => 'GM',
|
||||
'Georgia' => 'GE',
|
||||
'Germany' => 'DE',
|
||||
'Ghana' => 'GH',
|
||||
'Greece' => 'GR',
|
||||
'Greenland' => 'GL',
|
||||
'Guatemala' => 'GT',
|
||||
'Guinea' => 'GN',
|
||||
'Guinea-Bissau' => 'GW',
|
||||
'Guyana' => 'GY',
|
||||
'Haiti' => 'HT',
|
||||
'Honduras' => 'HN',
|
||||
'Hungary' => 'HU',
|
||||
'Iceland' => 'IS',
|
||||
'India' => 'IN',
|
||||
'Indonesia' => 'ID',
|
||||
'Iran' => 'IR',
|
||||
'Iraq' => 'IQ',
|
||||
'Ireland' => 'IE',
|
||||
'Israel' => 'IL',
|
||||
'Italy' => 'IT',
|
||||
'Jamaica' => 'JM',
|
||||
'Japan' => 'JP',
|
||||
'Jordan' => 'JO',
|
||||
'Kazakhstan' => 'KZ',
|
||||
'Kenya' => 'KE',
|
||||
'Korea' => 'KR',
|
||||
'Kuwait' => 'KW',
|
||||
'Kyrgyzstan' => 'KG',
|
||||
'Lao PDR' => 'LA',
|
||||
'Latvia' => 'LV',
|
||||
'Lebanon' => 'LB',
|
||||
'Lesotho' => 'LS',
|
||||
'Liberia' => 'LR',
|
||||
'Libya' => 'LY',
|
||||
'Lithuania' => 'LT',
|
||||
'Luxembourg' => 'LU',
|
||||
'Macedonia' => 'MK',
|
||||
'Madagascar' => 'MG',
|
||||
'Mainland China' => 'CN',
|
||||
'Malawi' => 'MW',
|
||||
'Malaysia' => 'MY',
|
||||
'Mali' => 'ML',
|
||||
'Mauritania' => 'MR',
|
||||
'Mexico' => 'MX',
|
||||
'Moldova' => 'MD',
|
||||
'Mongolia' => 'MN',
|
||||
'Montenegro' => 'ME',
|
||||
'Morocco' => 'MA',
|
||||
'Mozamb' => 'MZ',
|
||||
'Myanmar' => 'MM',
|
||||
'Namibia' => 'NA',
|
||||
'Nepal' => 'NP',
|
||||
'Netherlands' => 'NL',
|
||||
'New Caledonia' => 'NC',
|
||||
'New Zealand' => 'NZ',
|
||||
'Nicaragua' => 'NI',
|
||||
'Niger' => 'NE',
|
||||
'Nigeria' => 'NG',
|
||||
'Norway' => 'NO',
|
||||
'Oman' => 'OM',
|
||||
'Pakistan' => 'PK',
|
||||
'Palestine' => 'PS',
|
||||
'Panama' => 'PA',
|
||||
'Papua New Guinea' => 'PG',
|
||||
'Paraguay' => 'PY',
|
||||
'Peru' => 'PE',
|
||||
'Philippines' => 'PH',
|
||||
'Poland' => 'PL',
|
||||
'Portugal' => 'PT',
|
||||
'Puerto Rico' => 'PR',
|
||||
'Qatar' => 'QA',
|
||||
'Romania' => 'RO',
|
||||
'Russia' => 'RU',
|
||||
'Rwanda' => 'RW',
|
||||
'S. Sudan' => 'SS',
|
||||
'Saudi Arabia' => 'SA',
|
||||
'Senegal' => 'SN',
|
||||
'Serbia' => 'RS',
|
||||
'Sierra Leone' => 'SL',
|
||||
'Slovakia' => 'SK',
|
||||
'Slovenia' => 'SI',
|
||||
'Solomon Is.' => 'SB',
|
||||
'Somalia' => 'SO',
|
||||
'South Africa' => 'ZA',
|
||||
'Spain' => 'ES',
|
||||
'Sri Lanka' => 'LK',
|
||||
'Sudan' => 'SD',
|
||||
'Suriname' => 'SR',
|
||||
'Swaziland' => 'SZ',
|
||||
'Sweden' => 'SE',
|
||||
'Switzerland' => 'CH',
|
||||
'Syria' => 'SY',
|
||||
'Taiwan' => 'TW',
|
||||
'Tajikistan' => 'TJ',
|
||||
'Tanzania' => 'TZ',
|
||||
'Thailand' => 'TH',
|
||||
'Timor-Leste' => 'TL',
|
||||
'Togo' => 'TG',
|
||||
'Trinidad and Tobago' => 'TT',
|
||||
'Tunisia' => 'TN',
|
||||
'Turkey' => 'TR',
|
||||
'Turkmenistan' => 'TM',
|
||||
'Uganda' => 'UG',
|
||||
'Ukraine' => 'UA',
|
||||
'United Arab Emirates' => 'AE',
|
||||
'United Kingdom' => 'GB',
|
||||
'United States' => 'US',
|
||||
'Uruguay' => 'UY',
|
||||
'Uzbekistan' => 'UZ',
|
||||
'Vanuatu' => 'VU',
|
||||
'Venezuela' => 'VE',
|
||||
'Vietnam' => 'VN',
|
||||
'W. Sahara' => 'EH',
|
||||
'Yemen' => 'YE',
|
||||
'Zambia' => 'ZM',
|
||||
'Zimbabwe' => 'ZW'
|
||||
);
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$params = [
|
||||
'conditions' => [
|
||||
'Nationality !=' => ''
|
||||
]
|
||||
];
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$params['conditions']['AND'][] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Organisation = ClassRegistry::init('Organisation');
|
||||
$orgs = $this->Organisation->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['Organisation.nationality', 'COUNT(Organisation.nationality) AS frequency'],
|
||||
'conditions' => $params['conditions'],
|
||||
'group' => ['Organisation.nationality']
|
||||
]);
|
||||
$results = ['data' => [], 'scope' => 'Organisations'];
|
||||
foreach($orgs as $org) {
|
||||
$country = $org['Organisation']['nationality'];
|
||||
$count = $org['0']['frequency'];
|
||||
if (isset($this->countryCodes[$country])) {
|
||||
$countryCode = $this->countryCodes[$country];
|
||||
$results['data'][$countryCode] = $count;
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
class TrendingAttributesWidget
|
||||
{
|
||||
public $title = 'Trending Attribute values';
|
||||
public $render = 'BarChart';
|
||||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = array(
|
||||
'time_window' => 'The time window, going back in seconds, that should be included. (allows for filtering by days - example: 5d. -1 Will fetch all historic data)',
|
||||
'exclude' => 'List of values to exclude - for example "8.8.8.8".',
|
||||
'threshold' => 'Limits the number of displayed attribute values. Default: 10',
|
||||
'type' => 'List of Attribute types to include',
|
||||
'category' => 'List of Attribute categories to exclude',
|
||||
'to_ids' => 'A list of to_ids settings accepted for the data displayed ([0], [1], [0,1])',
|
||||
'org_filter' => 'List of organisation filters to exclude events by, based on organisation meta-data (Organisation.sector, Organisation.type, Organisation.nationality). Pre-pending a value with a "!" negates it.'
|
||||
);
|
||||
private $validOrgFilters = [
|
||||
'sector',
|
||||
'type',
|
||||
'national',
|
||||
'uuid',
|
||||
'local'
|
||||
];
|
||||
public $placeholder =
|
||||
'{
|
||||
"time_window": "7d",
|
||||
"threshold": 15,
|
||||
"org_filter": {
|
||||
"sector": ["Financial"]
|
||||
}
|
||||
}';
|
||||
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
|
||||
public $cacheLifetime = 3;
|
||||
|
||||
private function getOrgList($options)
|
||||
{
|
||||
$organisationModel = ClassRegistry::init('Organisation');
|
||||
if (!empty($options['org_filter']) && is_array($options['org_filter'])) {
|
||||
foreach ($this->validOrgFilters as $filterKey) {
|
||||
if (!empty($options['org_filter'][$filterKey])) {
|
||||
if ($filterKey === 'local') {
|
||||
$tempConditionBucket['Organisation.local'] = $options['org_filter']['local'];
|
||||
} else {
|
||||
if (!is_array($options['org_filter'][$filterKey])) {
|
||||
$options['org_filter'][$filterKey] = [$options['org_filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['org_filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$orgConditions[] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $organisationModel->find('column', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $orgConditions,
|
||||
'fields' => ['Organisation.id']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
/** @var Event $eventModel */
|
||||
$attributeModel = ClassRegistry::init('Attribute');
|
||||
$threshold = empty($options['threshold']) ? 10 : $options['threshold'];
|
||||
$time_window = empty($options['time_window']) ? (7 * 24 * 60 * 60) : (int)$options['time_window'];
|
||||
if (is_string($time_window) && substr($time_window, -1) === 'd') {
|
||||
$time_window = ((int)substr($time_window, 0, -1)) * 24 * 60 * 60;
|
||||
}
|
||||
$conditions = $time_window === -1 ? [] : ['timestamp >=' => time() - $time_window];
|
||||
$conditions['deleted'] = 0;
|
||||
$conditionsToParse = ['type', 'category', 'to_ids'];
|
||||
foreach ($conditionsToParse as $parsedCondition) {
|
||||
if (!empty($options[$parsedCondition])) {
|
||||
$conditions[$parsedCondition] = $options[$parsedCondition];
|
||||
}
|
||||
}
|
||||
if (!empty($options['exclude'])) {
|
||||
$conditions['value1 NOT IN'] = $options['exclude'];
|
||||
}
|
||||
if (!empty($options['org_filter'])) {
|
||||
$conditions['Event.orgc_id IN'] = $this->getOrgList($options);
|
||||
if (empty($conditions['Event.orgc_id IN'])) {
|
||||
$conditions['Event.orgc_id IN'] = [-1];
|
||||
}
|
||||
}
|
||||
$attributeModel->virtualFields['frequency'] = 0;
|
||||
if (!empty($user['Role']['perm_site_admin'])) {
|
||||
$values = $attributeModel->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['value1', 'count(Attribute.value1) as Attribute__frequency'],
|
||||
'group' => ['value1'],
|
||||
'conditions' => $conditions,
|
||||
'contain' => ['Event.orgc_id'],
|
||||
'order' => 'count(Attribute.value1) desc',
|
||||
'limit' => empty($options['threshold']) ? 10 : $options['threshold']
|
||||
]);
|
||||
} else {
|
||||
$conditions['AND'][] = [
|
||||
'OR' => [
|
||||
'Event.orgc_id' => $user['org_id'],
|
||||
|
||||
]
|
||||
];
|
||||
$values = $attributeModel->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['value1', 'count(Attribute.value1) as Attribute__frequency', 'distribution', 'sharing_group_id'],
|
||||
'group' => 'value1',
|
||||
'contain' => [
|
||||
'Event.org_id',
|
||||
'Event.distribution',
|
||||
'Event.sharing_group_id',
|
||||
'Object.distribution',
|
||||
'Object.sharing_group_id'
|
||||
],
|
||||
'conditions' => $conditions,
|
||||
'order' => 'count(Attribute.value1) desc',
|
||||
'limit' => empty($options['threshold']) ? 10 : $options['threshold']
|
||||
]);
|
||||
}
|
||||
$data = [];
|
||||
foreach ($values as $value) {
|
||||
$data[$value['Attribute']['value1']] = $value['Attribute']['frequency'];
|
||||
}
|
||||
return ['data' => $data];
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ class TrendingTagsWidget
|
|||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = array(
|
||||
'time_window' => 'The time window, going back in seconds, that should be included.',
|
||||
'time_window' => 'The time window, going back in seconds, that should be included. (allows for filtering by days - example: 5d. -1 Will fetch all historic data)',
|
||||
'exclude' => 'List of substrings to exclude tags by - for example "sofacy" would exclude any tag containing sofacy.',
|
||||
'include' => 'List of substrings to include tags by - for example "sofacy" would include any tag containing sofacy.',
|
||||
'threshold' => 'Limits the number of displayed tags. Default: 10',
|
||||
|
@ -16,23 +16,26 @@ class TrendingTagsWidget
|
|||
);
|
||||
public $placeholder =
|
||||
'{
|
||||
"time_window": "86400",
|
||||
"time_window": "7d",
|
||||
"threshold": 15,
|
||||
"exclude": ["tlp:", "pap:"],
|
||||
"include": ["misp-galaxy:", "my-internal-taxonomy"],
|
||||
"filter_event_tags": ["misp-galaxy:threat-actor="APT 29"],
|
||||
}';
|
||||
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
|
||||
public $cacheLifetime = 600;
|
||||
public $cacheLifetime = 3;
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
/** @var Event $eventModel */
|
||||
$eventModel = ClassRegistry::init('Event');
|
||||
$threshold = empty($options['threshold']) ? 10 : $options['threshold'];
|
||||
$params = [
|
||||
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window']),
|
||||
];
|
||||
$time_window = empty($options['time_window']) ? (7 * 24 * 60 * 60) : $options['time_window'];
|
||||
if (is_string($time_window) && substr($time_window, -1) === 'd') {
|
||||
$time_window = ((int)substr($time_window, 0, -1)) * 24 * 60 * 60;
|
||||
}
|
||||
$params = $time_window === -1 ? [] : ['timestamp' => time() - $time_window];
|
||||
|
||||
if (!empty($options['filter_event_tags'])) {
|
||||
$params['event_tags'] = $options['filter_event_tags'];
|
||||
}
|
||||
|
@ -48,6 +51,7 @@ class TrendingTagsWidget
|
|||
$events = $eventModel->fetchEvent($user, [
|
||||
'eventid' => $eventIds,
|
||||
'order' => 'Event.timestamp',
|
||||
'metadata' => 1
|
||||
]);
|
||||
|
||||
foreach ($events as $event) {
|
||||
|
@ -111,7 +115,6 @@ class TrendingTagsWidget
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,40 +5,82 @@ class UsageDataWidget
|
|||
public $render = 'SimpleList';
|
||||
public $width = 2;
|
||||
public $height = 5;
|
||||
public $params = array();
|
||||
public $description = 'Shows usage data / statistics.';
|
||||
public $cacheLifetime = false;
|
||||
public $autoRefreshDelay = 3;
|
||||
public $autoRefreshDelay = false;
|
||||
public $params = [
|
||||
'filter' => 'A list of filters by organisation meta information (nationality, sector, type, name, uuid) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
];
|
||||
private $User = null;
|
||||
private $Event = null;
|
||||
private $Correlation = null;
|
||||
private $Thread = null;
|
||||
private $AuthKey = null;
|
||||
|
||||
private $validFilterKeys = [
|
||||
'nationality',
|
||||
'sector',
|
||||
'type',
|
||||
'name',
|
||||
'uuid'
|
||||
];
|
||||
|
||||
private $validFields = [
|
||||
'Events',
|
||||
'Attributes',
|
||||
'Attributes / event',
|
||||
'Correlations',
|
||||
'Active proposals',
|
||||
'Users',
|
||||
'Users with PGP keys',
|
||||
'Organisations',
|
||||
'Local organisations',
|
||||
'Event creator orgs',
|
||||
'Average users / org',
|
||||
'Discussion threads',
|
||||
'Discussion posts'
|
||||
];
|
||||
|
||||
public function handler($user, $options = array()){
|
||||
$this->User = ClassRegistry::init('User');
|
||||
|
||||
$orgsCount = $this->User->Organisation->find('count');
|
||||
$localOrgsParams['conditions']['Organisation.local'] = 1;
|
||||
$localOrgsCount = $this->User->Organisation->find('count', $localOrgsParams);
|
||||
|
||||
$thisMonth = strtotime('first day of this month');
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$eventsCount = $this->Event->find('count', array('recursive' => -1));
|
||||
$eventsCountMonth = $this->Event->find('count', array('conditions' => array('Event.timestamp >' => $thisMonth), 'recursive' => -1));
|
||||
|
||||
$this->Attribute = ClassRegistry::init('Attribute');
|
||||
$attributesCount = $this->Attribute->find('count', array('conditions' => array('Attribute.deleted' => 0), 'recursive' => -1));
|
||||
$attributesCountMonth = $this->Attribute->find('count', array('conditions' => array('Attribute.timestamp >' => $thisMonth, 'Attribute.deleted' => 0), 'recursive' => -1));
|
||||
$attributesPerEvent = round($attributesCount / $eventsCount);
|
||||
|
||||
$this->Correlation = ClassRegistry::init('Correlation');
|
||||
$correlationsCount = $this->Correlation->find('count', array('recursive' => -1)) / 2;
|
||||
|
||||
$proposalsCount = $this->Event->ShadowAttribute->find('count', array('recursive' => -1, 'conditions' => array('deleted' => 0)));
|
||||
|
||||
$usersCount = $this->User->find('count', array('recursive' => -1));
|
||||
$usersCountPgp = $this->User->find('count', array('recursive' => -1, 'conditions' => array('User.gpgkey !=' => '')));
|
||||
$usersCountPgpPercentage = round(100* ($usersCountPgp / $usersCount), 1);
|
||||
$contributingOrgsCount = $this->Event->find('count', array('recursive' => -1, 'group' => array('Event.orgc_id')));
|
||||
$averageUsersPerOrg = round($usersCount / $localOrgsCount, 1);
|
||||
|
||||
$this->Thread = ClassRegistry::init('Thread');
|
||||
$this->Correlation = ClassRegistry::init('Correlation');
|
||||
$thisMonth = strtotime('first day of this month');
|
||||
$orgConditions = [];
|
||||
$orgIdList = null;
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$orgConditions[] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
$orgIdList = $this->User->Organisation->find('column', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $orgConditions,
|
||||
'fields' => ['Organisation.id']
|
||||
]);
|
||||
}
|
||||
$eventsCount = $this->getEventsCount($orgConditions, $orgIdList, $thisMonth);
|
||||
$attributesCount = $this->getAttributesCount($orgConditions, $orgIdList, $thisMonth);
|
||||
$usersCount = $this->getUsersCount($orgConditions, $orgIdList, $thisMonth);
|
||||
$usersCountPgp = $this->getUsersCountPgp($orgConditions, $orgIdList, $thisMonth);
|
||||
$localOrgsCount = $this->getLocalOrgsCount($orgConditions, $orgIdList, $thisMonth);
|
||||
|
||||
|
||||
$threadCount = $this->Thread->find('count', array('conditions' => array('Thread.post_count >' => 0), 'recursive' => -1));
|
||||
$threadCountMonth = $this->Thread->find('count', array('conditions' => array('Thread.date_created >' => date("Y-m-d H:i:s", $thisMonth), 'Thread.post_count >' => 0), 'recursive' => -1));
|
||||
|
||||
|
@ -47,21 +89,69 @@ class UsageDataWidget
|
|||
|
||||
//Monhtly data is not added to the widget at the moment, could optionally add these later and give user choice?
|
||||
|
||||
$statistics = array(
|
||||
array('title' => 'Events', 'value' => $eventsCount),
|
||||
array('title' => 'Attributes', 'value' => $attributesCount),
|
||||
array('title' => 'Attributes / event', 'value' => $attributesPerEvent),
|
||||
array('title' => 'Correlations', 'value' => $correlationsCount),
|
||||
array('title' => 'Active proposals', 'value' => $proposalsCount),
|
||||
array('title' => 'Users', 'value' => $usersCount),
|
||||
array('title' => 'Users with PGP keys', 'value' => $usersCountPgp . ' (' . $usersCountPgpPercentage . '%)'),
|
||||
array('title' => 'Organisations', 'value' => $orgsCount),
|
||||
array('title' => 'Local organisations', 'value' => $localOrgsCount),
|
||||
array('title' => 'Event creator orgs', 'value' => $contributingOrgsCount),
|
||||
array('title' => 'Average users / org', 'value' => $averageUsersPerOrg),
|
||||
array('title' => 'Discussions threads', 'value' => $threadCount),
|
||||
array('title' => 'Discussion posts', 'value' => $postCount)
|
||||
);
|
||||
$statistics = [
|
||||
'Events' => [
|
||||
'title' => 'Events',
|
||||
'value' => $eventsCount,
|
||||
'change' => $this->getEventsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Attributes' => [
|
||||
'title' => 'Attributes',
|
||||
'value' => $attributesCount,
|
||||
'change' => $this->getAttributesCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Attributes / event' => [
|
||||
'title' => 'Attributes / event',
|
||||
'value' => $eventsCount ? round($attributesCount / $eventsCount) : 0
|
||||
],
|
||||
'Correlations' => [
|
||||
'title' => 'Correlations',
|
||||
'value' => $this->getCorrelationsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Active proposals' => [
|
||||
'title' => 'Active proposals',
|
||||
'value' => $this->getProposalsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Users' => [
|
||||
'title' => 'Users',
|
||||
'value' => $usersCount,
|
||||
'change' => $this->getUsersCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Users with PGP keys' => [
|
||||
'title' => 'Users with PGP keys',
|
||||
'value' => sprintf(
|
||||
'%s (%s %%)',
|
||||
$usersCountPgp,
|
||||
$usersCount ? round(100* ($usersCountPgp / $usersCount), 1) : 0
|
||||
)
|
||||
],
|
||||
'Organisations' => [
|
||||
'title' => 'Organisations',
|
||||
'value' => $this->getOrgsCount($orgConditions, $orgIdList, $thisMonth),
|
||||
'change' => $this->getOrgsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Local organisations' => [
|
||||
'title' => 'Local organisations',
|
||||
'value' => $localOrgsCount,
|
||||
'change' => $this->getLocalOrgsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Event creator orgs' => [
|
||||
'title' => 'Event creator orgs', 'value' => $this->getContributingOrgsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Average users / org' => [
|
||||
'title' => 'Average users / org', 'value' => round($usersCount / $localOrgsCount, 1)
|
||||
],
|
||||
'Discussion threads' => [
|
||||
'title' => 'Discussions threads',
|
||||
'value' => $this->getThreadsCount($orgConditions, $orgIdList, $thisMonth),
|
||||
'change' => $this->getThreadsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
],
|
||||
'Discussion posts' => [
|
||||
'title' => 'Discussion posts',
|
||||
'value' => $this->getPostsCount($orgConditions, $orgIdList, $thisMonth),
|
||||
'change' => $this->getPostsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
]
|
||||
];
|
||||
if(!empty(Configure::read('Security.advanced_authkeys'))){
|
||||
$this->AuthKey = ClassRegistry::init('AuthKey');
|
||||
$authkeysCount = $this->AuthKey->find('count', array('recursive' => -1));
|
||||
|
@ -70,6 +160,233 @@ class UsageDataWidget
|
|||
return $statistics;
|
||||
}
|
||||
|
||||
private function getEventsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['AND'][] = ['Event.orgc_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Event->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getCorrelationsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['AND']['OR'][] = ['Correlation.org_id IN' => $orgIdList];
|
||||
$conditions['AND']['OR'][] = ['Correlation.1_org_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Correlation->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getEventsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['Event.timestamp >' => $thisMonth];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['AND'][] = ['Event.orgc_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Event->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getAttributesCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['Attribute.deleted' => 0];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['AND'][] = ['Event.orgc_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Event->Attribute->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'contain' => ['Event'],
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getAttributesCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['Attribute.timestamp >' => $thisMonth, 'Attribute.deleted' => 0];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['AND'][] = ['Event.orgc_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Event->Attribute->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'contain' => 'Event.orgc_id',
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getOrgsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
return $this->User->Organisation->find('count', [
|
||||
'conditions' => [
|
||||
'AND' => $orgConditions
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function getOrgsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$datetime = new DateTime();
|
||||
$datetime->setTimestamp($thisMonth);
|
||||
$thisMonth = $datetime->format('Y-m-d H:i:s');
|
||||
return $this->User->Organisation->find('count', [
|
||||
'conditions' => [
|
||||
'AND' => $orgConditions,
|
||||
'Organisation.date_created >' => $thisMonth
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function getLocalOrgsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
return $this->User->Organisation->find('count', [
|
||||
'conditions' => [
|
||||
'Organisation.local' => 1,
|
||||
'AND' => $orgConditions
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function getLocalOrgsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$datetime = new DateTime();
|
||||
$datetime->setTimestamp($thisMonth);
|
||||
$thisMonth = $datetime->format('Y-m-d H:i:s');
|
||||
return $this->User->Organisation->find('count', [
|
||||
'conditions' => [
|
||||
'Organisation.local' => 1,
|
||||
'AND' => $orgConditions,
|
||||
'Organisation.date_created >' => $thisMonth
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
private function getProposalsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['deleted' => 0];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['ShadowAttribute.org_id IN'] = $orgIdList;
|
||||
}
|
||||
return $this->Event->ShadowAttribute->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getUsersCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['User.org_id IN'] = $orgIdList;
|
||||
}
|
||||
return $this->User->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getUsersCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['User.date_created >' => $thisMonth];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['User.org_id IN'] = $orgIdList;
|
||||
}
|
||||
return $this->User->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getUsersCountPgp($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['User.gpgkey !=' => ''];
|
||||
if (!empty($orgIdList)) {
|
||||
$conditions['User.org_id IN'] = $orgIdList;
|
||||
}
|
||||
return $this->User->find('count', [
|
||||
'recursive' => -1,
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getContributingOrgsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [];
|
||||
if ($orgConditions) {
|
||||
$conditions['AND'][] = ['Event.orgc_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Event->find('count', [
|
||||
'recursive' => -1,
|
||||
'group' => ['Event.orgc_id'],
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
|
||||
private function getThreadsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = ['Thread.post_count >' => 0];
|
||||
if ($orgConditions) {
|
||||
$conditions['AND'][] = ['Thread.org_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Thread->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getThreadsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [
|
||||
'Thread.post_count >' => 0,
|
||||
'Thread.date_created >=' => $thisMonth
|
||||
];
|
||||
if ($orgConditions) {
|
||||
$conditions['AND'][] = ['Thread.org_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Thread->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getPostsCount($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [];
|
||||
if ($orgConditions) {
|
||||
$conditions['AND'][] = ['User.org_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Thread->Post->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'contain' => ['User.org_id'],
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
private function getPostsCountMonth($orgConditions, $orgIdList, $thisMonth)
|
||||
{
|
||||
$conditions = [
|
||||
'Post.date_created >=' => $thisMonth
|
||||
];
|
||||
if ($orgConditions) {
|
||||
$conditions['AND'][] = ['User.org_id IN' => $orgIdList];
|
||||
}
|
||||
return $this->Thread->Post->find('count', [
|
||||
'conditions' => $conditions,
|
||||
'contain' => ['User.org_id'],
|
||||
'recursive' => -1
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/* There is nothing sensitive in here.
|
||||
public function checkPermissions($user)
|
||||
{
|
||||
if (empty($user['Role']['perm_site_admin'])) {
|
||||
|
@ -77,4 +394,5 @@ class UsageDataWidget
|
|||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
class UserContributionToplistWidget
|
||||
{
|
||||
public $title = 'Contributor Top List (Users)';
|
||||
public $render = 'BarChart';
|
||||
public $description = 'The top contributors (users) in a selected time frame.';
|
||||
public $width = 3;
|
||||
public $height = 4;
|
||||
public $params = [
|
||||
'days' => 'How many days back should the list go - for example, setting 7 will only show contributions in the past 7 days. (integer)',
|
||||
'month' => 'Who contributed most this month? (boolean)',
|
||||
'year' => 'Which contributed most this year? (boolean)',
|
||||
'filter' => 'A list of filters by organisation meta information (nationality, sector, type, name, uuid, local (- expects a boolean or a list of boolean values)) to include. (dictionary, prepending values with ! uses them as a negation)',
|
||||
'limit' => 'Limits the number of displayed tags. Default: 10'
|
||||
];
|
||||
public $cacheLifetime = null;
|
||||
public $autoRefreshDelay = false;
|
||||
private $validFilterKeys = [
|
||||
'nationality',
|
||||
'sector',
|
||||
'type',
|
||||
'name',
|
||||
'uuid'
|
||||
];
|
||||
public $placeholder =
|
||||
'{
|
||||
"days": "7d",
|
||||
"threshold": 15,
|
||||
"filter": {
|
||||
"sector": "Financial"
|
||||
}
|
||||
}';
|
||||
private $Org = null;
|
||||
private $Event = null;
|
||||
|
||||
|
||||
private function timeConditions($options)
|
||||
{
|
||||
$limit = empty($options['limit']) ? 10 : $options['limit'];
|
||||
if (!empty($options['days'])) {
|
||||
$condition = strtotime(sprintf("-%s days", $options['days']));
|
||||
} else if (!empty($options['month'])) {
|
||||
$condition = strtotime('first day of this month 00:00:00', time());
|
||||
} else if (!empty($options['year'])) {
|
||||
$condition = strtotime('first day of this year 00:00:00', time());
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return $condition;
|
||||
}
|
||||
|
||||
|
||||
public function handler($user, $options = array())
|
||||
{
|
||||
$params = ['conditions' => []];
|
||||
$timeConditions = $this->timeConditions($options);
|
||||
if ($timeConditions) {
|
||||
$params['conditions']['AND'][] = ['Event.timestamp >=' => $timeConditions];
|
||||
}
|
||||
if (!empty($options['filter']) && is_array($options['filter'])) {
|
||||
foreach ($this->validFilterKeys as $filterKey) {
|
||||
if (!empty($options['filter'][$filterKey])) {
|
||||
if (!is_array($options['filter'][$filterKey])) {
|
||||
$options['filter'][$filterKey] = [$options['filter'][$filterKey]];
|
||||
}
|
||||
$tempConditionBucket = [];
|
||||
foreach ($options['filter'][$filterKey] as $value) {
|
||||
if ($value[0] === '!') {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' NOT IN'][] = mb_substr($value, 1);
|
||||
} else {
|
||||
$tempConditionBucket['Organisation.' . $filterKey . ' IN'][] = $value;
|
||||
}
|
||||
}
|
||||
if (!empty($tempConditionBucket)) {
|
||||
$params['conditions']['AND'][] = $tempConditionBucket;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($options['filter']['local'])) {
|
||||
$params['conditions']['AND']['local'] = $options['filter']['local'];
|
||||
}
|
||||
|
||||
$this->Org = ClassRegistry::init('Organisation');
|
||||
$org_ids = $this->Org->find('list', [
|
||||
'fields' => ['Organisation.id', 'Organisation.name'],
|
||||
'conditions' => $params['conditions']
|
||||
]);
|
||||
$userConditions = [];
|
||||
if (!empty($org_ids)) {
|
||||
$userConditions = ['User.org_id IN' => array_keys($org_ids)];
|
||||
}
|
||||
$user_ids = $this->Org->User->find('list', [
|
||||
'fields' => ['User.id', 'User.email'],
|
||||
'conditions' => $userConditions
|
||||
]);
|
||||
$conditions = empty($user_ids) ? [] : ['Event.user_id IN' => array_keys($user_ids)];
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$this->Event->virtualFields['frequency'] = 0;
|
||||
$users = $this->Event->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['user_id', 'count(Event.user_id) as Event__frequency'],
|
||||
'group' => ['user_id'],
|
||||
'conditions' => $conditions,
|
||||
'order' => 'count(Event.user_id) desc',
|
||||
'limit' => empty($options['limit']) ? 10 : $options['limit']
|
||||
]);
|
||||
$results = [];
|
||||
foreach($users as $user) {
|
||||
$results[$user_ids[$user['Event']['user_id']]] = $user['Event']['frequency'];
|
||||
}
|
||||
return ['data' => $results];
|
||||
}
|
||||
|
||||
public function checkPermissions($user)
|
||||
{
|
||||
if (empty(Configure::read('Security.disclose_user_emails')) && empty($user['Role']['perm_site_admin'])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -6584,7 +6584,15 @@ class Server extends AppModel
|
|||
'type' => 'boolean',
|
||||
'null' => true,
|
||||
'cli_only' => true
|
||||
]
|
||||
],
|
||||
'disclose_user_emails' => array(
|
||||
'level' => 0,
|
||||
'description' => __('Enable this setting to allow for the user e-mail addresses to be shown to non site-admin users. Keep in mind that in broad communities this can be abused.'),
|
||||
'value' => false,
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
),
|
||||
),
|
||||
'SecureAuth' => array(
|
||||
'branch' => 1,
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
array(
|
||||
'name' => __('Widgets Used'),
|
||||
'data_path' => 'Dashboard.widgets',
|
||||
'element' => 'list'
|
||||
'element' => 'allow_deny_list'
|
||||
),
|
||||
array(
|
||||
'name' => __('Selectable'),
|
||||
|
|
|
@ -15,10 +15,15 @@
|
|||
if (!empty($data['logarithmic'])) {
|
||||
$value = $data['logarithmic'][$entry];
|
||||
}
|
||||
$shortlabel = $entry;
|
||||
if (mb_strlen($shortlabel) > 30) {
|
||||
$shortlabel = mb_substr($shortlabel, 0, 30) . '...';
|
||||
}
|
||||
echo sprintf(
|
||||
'<tr><td style="%s">%s</td><td style="%s">%s</td></tr>',
|
||||
'text-align:right;width:33%;white-space:nowrap;',
|
||||
'<tr><td style="%s" title="%s">%s</td><td style="%s">%s</td></tr>',
|
||||
'text-align:right;width:35em;white-space:nowrap;',
|
||||
h($entry),
|
||||
h($shortlabel),
|
||||
'width:100%',
|
||||
sprintf(
|
||||
'<div title="%s" style="%s">%s%s</div>',
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
echo $this->element('genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $data['data'],
|
||||
'description' => empty($data['description']) ? false : $data['description'],
|
||||
'top_bar' => [],
|
||||
'fields' => $data['fields'],
|
||||
'title' => false,
|
||||
'description' => false,
|
||||
'pull' => 'right',
|
||||
'skip_pagination' => true,
|
||||
'actions' => []
|
||||
|
|
|
@ -18,12 +18,27 @@
|
|||
$element['value'] = h($element['value']);
|
||||
}
|
||||
}
|
||||
$change = '';
|
||||
if (!empty($element['change'])) {
|
||||
$change = (int)$element['change'];
|
||||
if ($change > 0) {
|
||||
$change = '<span class="green bold"> (+' . $change . ')</span>';
|
||||
} else {
|
||||
$change = '<span class="red bold"> (-' . $change . ')</span>';
|
||||
}
|
||||
}
|
||||
if (!empty($element['html_title'])) {
|
||||
$title = $element['html_title'];
|
||||
} else {
|
||||
$title = h($element['title']);
|
||||
}
|
||||
echo sprintf(
|
||||
'<div><span class="bold">%s</span>: <span class="%s">%s</span>%s</div>',
|
||||
h($element['title']),
|
||||
'<div><span class="bold">%s</span>: <span class="%s">%s</span>%s%s</div>',
|
||||
$title,
|
||||
empty($element['class']) ? 'blue' : h($element['class']),
|
||||
!isset($element['value']) ? '' : $element['value'],
|
||||
empty($element['html']) ? '' : $element['html']
|
||||
empty($element['html']) ? '' : $element['html'],
|
||||
$change
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
), true);
|
||||
}
|
||||
?>
|
||||
|
||||
<div id="world-map-<?= $randomNumber ?>" style="width: 600px; height: 400px"></div>
|
||||
<script>
|
||||
(function() { // variables and functions have their own scope (no override)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
$data = Hash::extract($row, $field['data_path']);
|
||||
$setup = [
|
||||
'allow' => [
|
||||
'name' => __('Allowed'),
|
||||
'color' => 'green'
|
||||
],
|
||||
'deny' => [
|
||||
'name' => __('Denied'),
|
||||
'color' => 'red'
|
||||
]
|
||||
];
|
||||
foreach ($setup as $state => $settings) {
|
||||
if (!empty($data[$state])) {
|
||||
echo sprintf(
|
||||
'<div class="bold %s">%s</div>',
|
||||
$settings['color'],
|
||||
$settings['name']
|
||||
);
|
||||
foreach ($data[$state] as $k => $element) {
|
||||
$data[$state][$k] = sprintf(
|
||||
'<span class="%s">%s</span>',
|
||||
$settings['color'],
|
||||
h($element)
|
||||
);
|
||||
}
|
||||
echo implode('<br />', $data[$state]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -78,21 +78,6 @@
|
|||
"misp_project_vetted": true,
|
||||
"scope_of_data_to_be_shared": "Cybersecurity Threat Intelligence including indicators, threat intelligence information, reports, contextual threat actor information or financial fraud information."
|
||||
},
|
||||
{
|
||||
"name": "Cognitive Security Collaborative",
|
||||
"uuid": "1ea46a83-cd51-40f5-a375-104e0acd6729",
|
||||
"org_uuid": "5e2dd31a-3bcc-45e8-ba7e-2ab890d945c8",
|
||||
"org_name": "Cogsec Collab",
|
||||
"description": "The Cognitive Security Collaborative operates as a sharing community dedicated to information operations.",
|
||||
"url": "https://www.cogsec-collab.org",
|
||||
"sector": "undefined",
|
||||
"nationality": "International",
|
||||
"type": "Vetted Information Sharing Community",
|
||||
"email": "misp@cogsec-collab.org",
|
||||
"pgp_key": "\r\n\r\n-----BEGIN PGP PUBLIC KEY BLOCK-----\r\n\r\nmQGNBF55bdcBDAC6+Fcey+0GcUw4iP4j15+/FylnvGa4wl8MRkYR5XryJn+n/O4s\r\nZbNCKpxwUA7lb2prn37lWMX7LswjvoxfmCTKi78UY1YH7Fqg3JG2PsV9Lw7uYnzC\r\nAImyAflzDpewo+eCF1aknvcbcbGkYFwdQ/37UfG/BkwCDQQGrBZ5EtL6CYXXNX/P\r\nX+4vYv23AVuchHvxeyW2dPLL3A6t3Mx8pZQBdN1cGZ1QAtE9IN0Yn2y+rMsNpDG4\r\ncOQ6bRqmue2I8JEB4AsQcufcqx69imBvBERsIZEyGZekLjmiuqDKI9Gti2VKZe/t\r\nxdl++gjplq6OAkdzXDGsMNtwxSk21IBrugAXK6K+4RPiMrPpBh81VGzBe2PRKUwT\r\nAZi06KZdaZudehvzIMLsNP5Aeep4+GXxoZ7Yrka/08SIv7SN5XY4o6xkli658Z+l\r\n8WAj2JiI684D/TK5MlvcBDQk1yKdDI2iC4eTFLkJ2PiDToUDT+vACrcnevstU+c8\r\nrNPFbvbB1DUIIo8AEQEAAbQ5Q29nbml0aXZlIFNlY3VyaXR5IENvbGxhYm9yYXRp\r\ndmUgPG1pc3BAY29nc2VjLWNvbGxhYi5vcmc+iQHUBBMBCAA+FiEEm65FjZ6Jbfp9\r\nCN50hA2Itf18R2cFAl55bdcCGwMFCQlmAYAFCwkIBwIGFQoJCAsCBBYCAwECHgEC\r\nF4AACgkQhA2Itf18R2e/ewv7BuCpmNIR0YOJld8RqrS4g5MV6eKJUuTRYUOxDyw9\r\nvgdpdvM1FgHPZ7pJcsijKQ+S+dL7ADmEbsCLWe1UhcwbnVRxJ0T+1yxRf6ONQA0/\r\ntRLmrcF4j6JCkl01irWRnYxMI1w1ABOQj4/J7BcTCzbYUdnxSuWhcZBqcsYIHf8J\r\nHnfbVd7OIML/80IRZbRXn1ST6OeXK9RpzqO7bnfPGnd506dt8sfHCWRidUSv2max\r\nrsi9xSyXeSKSNPQFVBgYnMVwBVUGIaWTnt7Ly4I8Bs5P9NWUpLYrRgYLMbDzLWaD\r\nxX7qNQjAKkNCx9k7qQN0Ck9YqeUIuJQPq2doGuLKnqjJBXizsXbAFqcKitQz7WV2\r\nPUsN/QUguVyZbhy7oJELlWDiDWxS6EwpU+q0SODHjCFKoUXvWFkk9bz1K4/kLDFO\r\nOdTABp7i65nJst5b3pVXimoTKqW7JRyCUWz3aaaqjWSTPKP2GmQbxOwM86rgmnGX\r\nqq8Ces6LQw6zGw08ubDDotEKuQGNBF55bdcBDACbmsVMV7azLYys6iMXTLVERasT\r\nUnw8FpKADA2uDgQme5o3CjeFtBBkgBNe8zdOEEslggETVmntp4n6woQzOknDHNx/\r\nVMliUaGuIYgmC8hTDTF269fdRTpKMrcwu2aBEUpHpG7Xvz91HIr213FTwU0LLq0g\r\n+DefSlwdcMPJiCUqshLw8q/D3qVg/VYVen5li55RQBBFLgYYNgag3WnSejE41uqz\r\nvt40FZ4C88Pj0I3f+PRtfHHeXTZehUjs3+W4jn1fLWNmbIScmIhwp/Vqh8R7JHf2\r\n69UGgWr4cOaLGh6C2Io+TVJ+Sq7TMt47qB6eO53Vr2nyizXTxjrmAWqjw3OLc8QX\r\nWsjbpTMqUaPisnCpog/3SqnE4Fe2rQYkroQao6dRL3FrmgvnyhLgjUtjk6fAfx1+\r\nH6fQFH/JJGCNefG9AWo41Er3oHGoV0yqlI697uk0QGdx/848hc0gXLrus82bw+BI\r\nx36ycevxkpmfvzC8lew/vLEB7t/jqXH2H9Qqtm0AEQEAAYkBvAQYAQgAJhYhBJuu\r\nRY2eiW36fQjedIQNiLX9fEdnBQJeeW3XAhsMBQkJZgGAAAoJEIQNiLX9fEdnmYsM\r\nAJzX6MCYoGPED1VXMoPXVS9s7V7hv+0Q4SKcoUxqROwA0wb3NwvdnzO/WAQlzIIj\r\ny1Sk9VX8qZkATN7+nti8jfhKnlMVqAXFFg9fMsq68WlTzHiyGm06DnM2DXBvdLRT\r\nwbcm5H4Ly1/bCFww6Spbxo3zScrSCeRrIHHGOHEzr/vhcZavRDpFmdpTCD6ID7oG\r\nw5jR6GdSCpvBT6Lq7M2xe6cVw/A9z5tE3cIf75uikKfch8HFVV2l1B9XLJVpvhqv\r\nYf+kUa7l7VP893yyTyf9G6SSaS77VKlHxn+OQ9AX+wdgSpD5SgVkvRFXejXw8oIZ\r\nBeTNYTvYYgV75ApnvT+hyeirGDCRRiTiuva0ijd71PzTRk+5Ad80rav1Jy864dUt\r\nDcSklY5T+wjJf7kb/3nIE5vqO/3YkJxdDTvZM23T+IZsCvamQ5pyyp+bP3HTAZkr\r\no6oiGFXbv5OF6/wkUG6vQ5w1RCUQVLfrM6Dh675dx/sdI+p0JMt6BlvlRUJSofu0\r\nWw==\r\n=4aXp\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n",
|
||||
"misp_project_vetted": true,
|
||||
"scope_of_data_to_be_shared": "Information Operation Threat Intelligence including disinformation, indicators, threat intelligence information, reports, contextual threat actor information or financial fraud information."
|
||||
},
|
||||
{
|
||||
"name": "COVID-19 MISP community",
|
||||
"uuid": "5e59659e-8e24-4e5d-b3fa-2ba744b7dd05",
|
||||
|
|
Loading…
Reference in New Issue