mirror of https://github.com/MISP/MISP
commit
e4a00d067a
2
PyMISP
2
PyMISP
|
@ -1 +1 @@
|
|||
Subproject commit 357096f24c4f8d7dac87dfe0b9edad4f924f27a3
|
||||
Subproject commit c2e9663765e83f1a4aa70099546bec653ed770e7
|
|
@ -1 +1 @@
|
|||
{"major":2, "minor":4, "hotfix":142}
|
||||
{"major":2, "minor":4, "hotfix":143}
|
||||
|
|
|
@ -28,10 +28,11 @@
|
|||
Router::connect('/', array('controller' => 'events', 'action' => 'index'));
|
||||
|
||||
// admin Paginator
|
||||
Router::connect('/whitelists/admin_index/*', array('controller' => 'whitelists', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/allowedlists/admin_index/*', array('controller' => 'allowedlists', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/users/admin_index/*', array('controller' => 'users', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/roles/admin_index/*', array('controller' => 'roles', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/logs/admin_search/*', array('controller' => 'logs', 'action' => 'search', 'admin' => true));
|
||||
Router::connect('/audit_logs/admin_index/*', array('controller' => 'audit_logs', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/logs/admin_index/*', array('controller' => 'logs', 'action' => 'index', 'admin' => true));
|
||||
Router::connect('/regexp/admin_index/*', array('controller' => 'regexp', 'action' => 'index', 'admin' => true));
|
||||
|
||||
|
|
|
@ -445,6 +445,7 @@ class EventShell extends AppShell
|
|||
$inputData = $tempFile->read();
|
||||
$inputData = json_decode($inputData, true);
|
||||
$tempFile->delete();
|
||||
Configure::write('CurrentUserId', $inputData['user']['id']);
|
||||
$this->Event->processFreeTextData(
|
||||
$inputData['user'],
|
||||
$inputData['attributes'],
|
||||
|
@ -465,6 +466,7 @@ class EventShell extends AppShell
|
|||
$tempFile = new File(APP . 'tmp/cache/ingest' . DS . $inputFile);
|
||||
$inputData = json_decode($tempFile->read(), true);
|
||||
$tempFile->delete();
|
||||
Configure::write('CurrentUserId', $inputData['user']['id']);
|
||||
$this->Event->processModuleResultsData(
|
||||
$inputData['user'],
|
||||
$inputData['misp_format'],
|
||||
|
@ -530,6 +532,7 @@ class EventShell extends AppShell
|
|||
if (empty($user)) {
|
||||
$this->error("User with ID $userId does not exists.");
|
||||
}
|
||||
Configure::write('CurrentUserId', $user['id']); // for audit logging purposes
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,150 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @property Log $Log
|
||||
* @property AuditLog $AuditLog
|
||||
* @property Server $Server
|
||||
*/
|
||||
class LogShell extends AppShell
|
||||
{
|
||||
public $uses = ['Log', 'AuditLog', 'Server'];
|
||||
|
||||
public function getOptionParser()
|
||||
{
|
||||
$parser = parent::getOptionParser();
|
||||
$parser->addSubcommand('auditStatistics', [
|
||||
'help' => __('Show statistics from audit logs.'),
|
||||
]);
|
||||
$parser->addSubcommand('statistics', [
|
||||
'help' => __('Show statistics from logs.'),
|
||||
]);
|
||||
$parser->addSubcommand('export', [
|
||||
'help' => __('Export logs to compressed file in JSON Lines format (one JSON encoded line per entry).'),
|
||||
'parser' => array(
|
||||
'arguments' => array(
|
||||
'file' => ['help' => __('Path to output file'), 'required' => true],
|
||||
),
|
||||
),
|
||||
]);
|
||||
return $parser;
|
||||
}
|
||||
|
||||
public function export()
|
||||
{
|
||||
list($path) = $this->args;
|
||||
|
||||
if (file_exists($path)) {
|
||||
$this->error("File $path already exists");
|
||||
}
|
||||
|
||||
$file = gzopen($path, 'wb4'); // Compression level 4 is best compromise between time and size
|
||||
if ($file === false) {
|
||||
$this->error("Could not open $path for writing");
|
||||
}
|
||||
|
||||
$rows = $this->Log->query("SELECT TABLE_ROWS FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'logs';");
|
||||
/** @var ProgressShellHelper $progress */
|
||||
$progress = $this->helper('progress');
|
||||
$progress->init([
|
||||
'total' => $rows[0]['TABLES']['TABLE_ROWS'], // just estimate, but fast
|
||||
'width' => 50,
|
||||
]);
|
||||
|
||||
$lastId = 0;
|
||||
while (true) {
|
||||
$logs = $this->Log->find('all', [
|
||||
'conditions' => ['id >' => $lastId], // much faster than offset
|
||||
'recursive' => -1,
|
||||
'limit' => 100000,
|
||||
'order' => ['id ASC'],
|
||||
]);
|
||||
if (empty($logs)) {
|
||||
break;
|
||||
}
|
||||
$lines = '';
|
||||
foreach ($logs as $log) {
|
||||
$log = $log['Log'];
|
||||
foreach (['id', 'model_id', 'user_id'] as $field) {
|
||||
$log[$field] = (int)$log[$field]; // Convert to int to save space
|
||||
}
|
||||
if (empty($log['description'])) {
|
||||
unset($log['description']);
|
||||
}
|
||||
if (empty($log['ip'])) {
|
||||
unset($log['ip']);
|
||||
}
|
||||
$log['created'] = strtotime($log['created']); // to save space
|
||||
if ($log['id'] > $lastId) {
|
||||
$lastId = $log['id'];
|
||||
}
|
||||
$lines .= json_encode($log, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR) . "\n";
|
||||
}
|
||||
if (gzwrite($file, $lines) === false) {
|
||||
$this->error("Could not write data to $path");
|
||||
}
|
||||
$progress->increment(count($logs));
|
||||
$progress->draw();
|
||||
}
|
||||
gzclose($file);
|
||||
$this->out('Done');
|
||||
}
|
||||
|
||||
public function statistics()
|
||||
{
|
||||
$count = $this->Log->find('count');
|
||||
$first = $this->Log->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['created'],
|
||||
'order' => ['id ASC'],
|
||||
]);
|
||||
$last = $this->Log->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['created'],
|
||||
'order' => ['id DESC'],
|
||||
]);
|
||||
|
||||
$this->out(str_pad(__('Count:'), 20) . $count);
|
||||
$this->out(str_pad(__('First:'), 20) . $first['Log']['created']);
|
||||
$this->out(str_pad(__('Last:'), 20) . $last['Log']['created']);
|
||||
|
||||
$usage = $this->Server->dbSpaceUsage()['logs'];
|
||||
$this->out(str_pad(__('Data size:'), 20) . CakeNumber::toReadableSize($usage['data_in_bytes']));
|
||||
$this->out(str_pad(__('Index size:'), 20) . CakeNumber::toReadableSize($usage['index_in_bytes']));
|
||||
$this->out(str_pad(__('Reclaimable size:'), 20) . CakeNumber::toReadableSize($usage['reclaimable_in_bytes']), 2);
|
||||
}
|
||||
|
||||
public function auditStatistics()
|
||||
{
|
||||
$count = $this->AuditLog->find('count');
|
||||
$first = $this->AuditLog->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['created'],
|
||||
'order' => ['id ASC'],
|
||||
]);
|
||||
$last = $this->AuditLog->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['created'],
|
||||
'order' => ['id DESC'],
|
||||
]);
|
||||
|
||||
$this->out(str_pad(__('Count:'), 20) . $count);
|
||||
$this->out(str_pad(__('First:'), 20) . $first['AuditLog']['created']);
|
||||
$this->out(str_pad(__('Last:'), 20) . $last['AuditLog']['created']);
|
||||
|
||||
$usage = $this->Server->dbSpaceUsage()['audit_logs'];
|
||||
$this->out(str_pad(__('Data size:'), 20) . CakeNumber::toReadableSize($usage['data_in_bytes']));
|
||||
$this->out(str_pad(__('Index size:'), 20) . CakeNumber::toReadableSize($usage['index_in_bytes']));
|
||||
$this->out(str_pad(__('Reclaimable size:'), 20) . CakeNumber::toReadableSize($usage['reclaimable_in_bytes']), 2);
|
||||
|
||||
// Just to fetch compressionStats
|
||||
$this->AuditLog->find('column', [
|
||||
'fields' => ['change'],
|
||||
]);
|
||||
|
||||
$this->out('Change field:');
|
||||
$this->out('-------------');
|
||||
$this->out(str_pad(__('Compressed items:'), 20) . $this->AuditLog->compressionStats['compressed']);
|
||||
$this->out(str_pad(__('Uncompressed size:'), 20) . CakeNumber::toReadableSize($this->AuditLog->compressionStats['bytes_uncompressed']));
|
||||
$this->out(str_pad(__('Compressed size:'), 20) . CakeNumber::toReadableSize($this->AuditLog->compressionStats['bytes_compressed']));
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ class AllowedlistsController extends AppController
|
|||
if (!$this->userRole['perm_regexp_access']) {
|
||||
$this->redirect(array('controller' => 'regexp', 'action' => 'index', 'admin' => false));
|
||||
}
|
||||
$this->set('action', 'add');
|
||||
$this->AdminCrud->adminAdd();
|
||||
}
|
||||
|
||||
|
@ -30,6 +31,7 @@ class AllowedlistsController extends AppController
|
|||
$this->redirect(array('controller' => 'allowedlists', 'action' => 'index', 'admin' => false));
|
||||
}
|
||||
$this->AdminCrud->adminIndex();
|
||||
$this->render('index');
|
||||
}
|
||||
|
||||
public function admin_edit($id = null)
|
||||
|
@ -38,6 +40,9 @@ class AllowedlistsController extends AppController
|
|||
$this->redirect(array('controller' => 'allowedlists', 'action' => 'index', 'admin' => false));
|
||||
}
|
||||
$this->AdminCrud->adminEdit($id);
|
||||
$this->set('action', 'edit');
|
||||
$this->set('id', $id);
|
||||
$this->render('admin_add');
|
||||
}
|
||||
|
||||
public function admin_delete($id = null)
|
||||
|
|
|
@ -26,7 +26,7 @@ class AppController extends Controller
|
|||
public $helpers = array('OrgImg', 'FontAwesome', 'UserName', 'DataPathCollector');
|
||||
|
||||
private $__queryVersion = '129';
|
||||
public $pyMispVersion = '2.4.142';
|
||||
public $pyMispVersion = '2.4.143';
|
||||
public $phpmin = '7.2';
|
||||
public $phprec = '7.4';
|
||||
public $phptoonew = '8.0';
|
||||
|
|
|
@ -1257,7 +1257,7 @@ class AttributesController extends AppController
|
|||
// tags to remove
|
||||
$tags = $this->Attribute->AttributeTag->getAttributesTags($attributes);
|
||||
$tagItemsRemove = array();
|
||||
foreach ($tags as $k => $tag) {
|
||||
foreach ($tags as $tag) {
|
||||
$tagName = $tag['name'];
|
||||
$tagItemsRemove[] = array(
|
||||
'name' => $tagName,
|
||||
|
@ -1275,9 +1275,9 @@ class AttributesController extends AppController
|
|||
unset($tags);
|
||||
|
||||
// clusters to remove
|
||||
$clusters = $this->Attribute->AttributeTag->getAttributesClusters($attributes);
|
||||
$clusters = $this->Attribute->AttributeTag->getAttributesClusters($this->Auth->user(), $attributes);
|
||||
$clusterItemsRemove = array();
|
||||
foreach ($clusters as $k => $cluster) {
|
||||
foreach ($clusters as $cluster) {
|
||||
$name = $cluster['value'];
|
||||
$optionName = $cluster['value'];
|
||||
$synom = $cluster['synonyms_string'] !== '' ? " ({$cluster['synonyms_string']})" : '';
|
||||
|
@ -1304,7 +1304,7 @@ class AttributesController extends AppController
|
|||
'conditions' => array('published' => true)
|
||||
));
|
||||
$clusterItemsAdd = array();
|
||||
foreach ($clusters as $k => $cluster) {
|
||||
foreach ($clusters as $cluster) {
|
||||
$clusterItemsAdd[] = array(
|
||||
'name' => $cluster['GalaxyCluster']['value'],
|
||||
'value' => $cluster['GalaxyCluster']['id']
|
||||
|
@ -1346,6 +1346,7 @@ class AttributesController extends AppController
|
|||
$this->set('clusterItemsRemove', $clusterItemsRemove);
|
||||
$this->set('options', array( // set chosen (select picker) options
|
||||
'multiple' => -1,
|
||||
'autofocus' => false,
|
||||
'disabledSubmitButton' => true,
|
||||
'flag_redraw_chosen' => true,
|
||||
'select_options' => array(
|
||||
|
@ -2963,7 +2964,7 @@ class AttributesController extends AppController
|
|||
if ($attribute['Attribute']['disable_correlation']) {
|
||||
$attribute['Attribute']['disable_correlation'] = 0;
|
||||
$this->Attribute->save($attribute);
|
||||
$this->Attribute->__afterSaveCorrelation($attribute['Attribute'], false, $attribute);
|
||||
ClassRegistry::init('Correlation')->afterSaveCorrelation($attribute['Attribute'], false, $attribute);
|
||||
} else {
|
||||
$attribute['Attribute']['disable_correlation'] = 1;
|
||||
$this->Attribute->save($attribute);
|
||||
|
|
|
@ -0,0 +1,586 @@
|
|||
<?php
|
||||
App::uses('AppController', 'Controller');
|
||||
App::uses('AuditLog', 'Model');
|
||||
|
||||
/**
|
||||
* @property AuditLog $AuditLog
|
||||
*/
|
||||
class AuditLogsController extends AppController
|
||||
{
|
||||
public $components = [
|
||||
'Security',
|
||||
'RequestHandler',
|
||||
];
|
||||
|
||||
/** @var array */
|
||||
private $actions;
|
||||
|
||||
/** @var string[] */
|
||||
private $models = [
|
||||
'AdminSetting',
|
||||
'Attribute',
|
||||
'Allowedlist',
|
||||
'AuthKey',
|
||||
'Cerebrate',
|
||||
'CorrelationExclusion',
|
||||
'Event',
|
||||
'EventBlocklist',
|
||||
'Feed',
|
||||
'DecayingModel',
|
||||
'Object',
|
||||
'ObjectTemplate',
|
||||
'Organisation',
|
||||
'OrgBlocklist',
|
||||
'Post',
|
||||
'Regexp',
|
||||
'Role',
|
||||
'Server',
|
||||
'ShadowAttribute',
|
||||
'SharingGroup',
|
||||
'Tag',
|
||||
'TagCollection',
|
||||
'TagCollectionTag',
|
||||
'Task',
|
||||
'Taxonomy',
|
||||
'Template',
|
||||
'Thread',
|
||||
'User',
|
||||
'UserSetting',
|
||||
'Galaxy',
|
||||
'GalaxyCluster',
|
||||
'GalaxyClusterBlocklist',
|
||||
'GalaxyClusterRelation',
|
||||
'News',
|
||||
'Warninglist',
|
||||
];
|
||||
|
||||
public $paginate = [
|
||||
'recursive' => -1,
|
||||
'limit' => 60,
|
||||
'fields' => ['id', 'created', 'user_id', 'org_id', 'action', 'model', 'model_id', 'model_title', 'event_id', 'change'],
|
||||
'contain' => [
|
||||
'User' => ['fields' => ['id', 'email', 'org_id']],
|
||||
'Organisation' => ['fields' => ['id', 'name', 'uuid']],
|
||||
],
|
||||
'order' => [
|
||||
'AuditLog.id' => 'DESC'
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->actions = [
|
||||
AuditLog::ACTION_ADD => __('Add'),
|
||||
AuditLog::ACTION_EDIT => __('Edit'),
|
||||
AuditLog::ACTION_SOFT_DELETE => __('Soft delete'),
|
||||
AuditLog::ACTION_DELETE => __('Delete'),
|
||||
AuditLog::ACTION_UNDELETE => __('Undelete'),
|
||||
AuditLog::ACTION_TAG => __('Tag'),
|
||||
AuditLog::ACTION_TAG_LOCAL => __('Tag'),
|
||||
AuditLog::ACTION_REMOVE_TAG => __('Remove tag'),
|
||||
AuditLog::ACTION_REMOVE_TAG_LOCAL => __('Remove tag'),
|
||||
AuditLog::ACTION_GALAXY => __('Galaxy cluster'),
|
||||
AuditLog::ACTION_GALAXY_LOCAL => __('Galaxy cluster'),
|
||||
AuditLog::ACTION_REMOVE_GALAXY => __('Remove galaxy cluster'),
|
||||
AuditLog::ACTION_REMOVE_GALAXY_LOCAL => __('Remove galaxy cluster'),
|
||||
AuditLog::ACTION_PUBLISH => __('Publish'),
|
||||
AuditLog::ACTION_PUBLISH_SIGHTINGS => __('Publish sightings'),
|
||||
];
|
||||
}
|
||||
|
||||
public function admin_index()
|
||||
{
|
||||
$this->paginate['fields'][] = 'ip';
|
||||
$this->paginate['fields'][] = 'request_type';
|
||||
$this->paginate['fields'][] = 'authkey_id';
|
||||
|
||||
if ($this->_isRest()) {
|
||||
$this->paginate['fields'][] = 'request_id';
|
||||
}
|
||||
|
||||
$this->paginate['conditions'] = $this->__searchConditions();
|
||||
$list = $this->paginate();
|
||||
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->viewData($list, 'json');
|
||||
}
|
||||
|
||||
$list = $this->__appendModelLinks($list);
|
||||
foreach ($list as $k => $item) {
|
||||
$list[$k]['AuditLog']['action_human'] = $this->actions[$item['AuditLog']['action']];
|
||||
}
|
||||
|
||||
$this->set('list', $list);
|
||||
$this->set('actions', [
|
||||
AuditLog::ACTION_ADD => __('Add'),
|
||||
AuditLog::ACTION_EDIT => __('Edit'),
|
||||
AuditLog::ACTION_SOFT_DELETE => __('Soft delete'),
|
||||
AuditLog::ACTION_DELETE => __('Delete'),
|
||||
AuditLog::ACTION_UNDELETE => __('Undelete'),
|
||||
AuditLog::ACTION_TAG . '||' . AuditLog::ACTION_TAG_LOCAL => __('Tag'),
|
||||
AuditLog::ACTION_REMOVE_TAG . '||' . AuditLog::ACTION_REMOVE_TAG_LOCAL => __('Remove tag'),
|
||||
AuditLog::ACTION_GALAXY . '||' . AuditLog::ACTION_GALAXY_LOCAL => __('Galaxy cluster'),
|
||||
AuditLog::ACTION_REMOVE_GALAXY . '||' . AuditLog::ACTION_REMOVE_GALAXY_LOCAL => __('Remove galaxy cluster'),
|
||||
AuditLog::ACTION_PUBLISH => __('Publish'),
|
||||
AuditLog::ACTION_PUBLISH_SIGHTINGS => $this->actions[AuditLog::ACTION_PUBLISH_SIGHTINGS],
|
||||
]);
|
||||
$models = $this->models;
|
||||
sort($models);
|
||||
$this->set('models', $models);
|
||||
$this->set('title_for_layout', __('Audit logs'));
|
||||
}
|
||||
|
||||
public function eventIndex($eventId, $org = null)
|
||||
{
|
||||
$this->loadModel('Event');
|
||||
$event = $this->Event->fetchSimpleEvent($this->Auth->user(), $eventId);
|
||||
if (empty($event)) {
|
||||
throw new NotFoundException('Invalid event.');
|
||||
}
|
||||
|
||||
$this->paginate['conditions'] = $this->__createEventIndexConditions($event);
|
||||
|
||||
if ($org) {
|
||||
$org = $this->AuditLog->Organisation->fetchOrg($org);
|
||||
if ($org) {
|
||||
$this->paginate['conditions']['AND']['org_id'] = $org['id'];
|
||||
} else {
|
||||
$this->paginate['conditions']['AND']['org_id'] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
$list = $this->paginate();
|
||||
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
// Remove all user info about users from different org
|
||||
$this->loadModel('User');
|
||||
$orgUserIds = $this->User->find('column', array(
|
||||
'conditions' => ['User.org_id' => $this->Auth->user('org_id')],
|
||||
'fields' => ['User.id'],
|
||||
));
|
||||
foreach ($list as $k => $item) {
|
||||
if ($item['AuditLog']['user_id'] == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!in_array($item['User']['id'], $orgUserIds)) {
|
||||
unset($list[$k]['User']);
|
||||
unset($list[$k]['AuditLog']['user_id']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->viewData($list, 'json');
|
||||
}
|
||||
|
||||
foreach ($list as $k => $item) {
|
||||
$list[$k]['AuditLog']['action_human'] = $this->actions[$item['AuditLog']['action']];
|
||||
}
|
||||
|
||||
$this->set('list', $list);
|
||||
$this->set('event', $event);
|
||||
$this->set('mayModify', $this->__canModifyEvent($event));
|
||||
$this->set('title_for_layout', __('Audit logs for event #%s', $event['Event']['id']));
|
||||
}
|
||||
|
||||
public function fullChange($id)
|
||||
{
|
||||
$log = $this->AuditLog->find('first', [
|
||||
'conditions' => ['id' => $id],
|
||||
'recursive' => -1,
|
||||
'fields' => ['change', 'action'],
|
||||
]);
|
||||
if (empty($log)) {
|
||||
throw new Exception('Log not found.');
|
||||
}
|
||||
$this->set('log', $log);
|
||||
}
|
||||
|
||||
public function returnDates($org = 'all')
|
||||
{
|
||||
if (!$this->Auth->user('Role')['perm_sharing_group'] && !empty(Configure::read('Security.hide_organisation_index_from_users'))) {
|
||||
if ($org !== 'all' && $org !== $this->Auth->user('Organisation')['name']) {
|
||||
throw new MethodNotAllowedException('Invalid organisation.');
|
||||
}
|
||||
}
|
||||
|
||||
// Fetching dates can be slow, so to allow concurrent requests, we can close sessions to release session lock
|
||||
session_write_close();
|
||||
|
||||
$data = $this->AuditLog->returnDates($org);
|
||||
return $this->RestResponse->viewData($data, $this->response->type());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function __searchConditions()
|
||||
{
|
||||
$params = $this->IndexFilter->harvestParameters([
|
||||
'ip',
|
||||
'user',
|
||||
'request_id',
|
||||
'authkey_id',
|
||||
'model',
|
||||
'model_id',
|
||||
'event_id',
|
||||
'model_title',
|
||||
'action',
|
||||
'org',
|
||||
'created',
|
||||
'request_type',
|
||||
]);
|
||||
|
||||
$qbRules = [];
|
||||
foreach ($params as $key => $value) {
|
||||
if ($key === 'model' && strpos($value, ':') !== false) {
|
||||
$parts = explode(':', $value);
|
||||
$qbRules[] = [
|
||||
'id' => 'model',
|
||||
'value' => $parts[0],
|
||||
];
|
||||
$qbRules[] = [
|
||||
'id' => 'model_id',
|
||||
'value' => $parts[1],
|
||||
];
|
||||
} elseif ($key === 'created') {
|
||||
$qbRules[] = [
|
||||
'id' => $key,
|
||||
'operator' => is_array($value) ? 'between' : 'greater_or_equal',
|
||||
'value' => $value,
|
||||
];
|
||||
} else {
|
||||
if (is_array($value)) {
|
||||
$value = implode('||', $value);
|
||||
}
|
||||
$qbRules[] = [
|
||||
'id' => $key,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
}
|
||||
$this->set('qbRules', $qbRules);
|
||||
|
||||
$conditions = [];
|
||||
if (isset($params['user'])) {
|
||||
if (strtoupper($params['user']) === 'SYSTEM') {
|
||||
$conditions['AuditLog.user_id'] = 0;
|
||||
} else if (is_numeric($params['user'])) {
|
||||
$conditions['AuditLog.user_id'] = $params['user'];
|
||||
} else {
|
||||
$user = $this->User->find('first', [
|
||||
'conditions' => ['User.email' => $params['user']],
|
||||
'fields' => ['id'],
|
||||
]);
|
||||
if (!empty($user)) {
|
||||
$conditions['AuditLog.user_id'] = $user['User']['id'];
|
||||
} else {
|
||||
$conditions['AuditLog.user_id'] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($params['ip'])) {
|
||||
$conditions['AuditLog.ip'] = inet_pton($params['ip']);
|
||||
}
|
||||
if (isset($params['authkey_id'])) {
|
||||
$conditions['AuditLog.authkey_id'] = $params['authkey_id'];
|
||||
}
|
||||
if (isset($params['request_id'])) {
|
||||
$conditions['AuditLog.request_id'] = $params['request_id'];
|
||||
}
|
||||
if (isset($params['request_type'])) {
|
||||
$conditions['AuditLog.request_type'] = $params['request_type'];
|
||||
}
|
||||
if (isset($params['model'])) {
|
||||
$conditions['AuditLog.model'] = $params['model'];
|
||||
}
|
||||
if (isset($params['model_id'])) {
|
||||
$conditions['AuditLog.model_id'] = $params['model_id'];
|
||||
}
|
||||
if (isset($params['event_id'])) {
|
||||
$conditions['AuditLog.event_id'] = $params['event_id'];
|
||||
}
|
||||
if (isset($params['model_title'])) {
|
||||
$conditions['AuditLog.model_title LIKE'] = '%' . $params['model_title'] . '%';
|
||||
}
|
||||
if (isset($params['action'])) {
|
||||
$conditions['AuditLog.action'] = $params['action'];
|
||||
}
|
||||
if (isset($params['org'])) {
|
||||
if (is_numeric($params['org'])) {
|
||||
$conditions['AuditLog.org_id'] = $params['org'];
|
||||
} else {
|
||||
$org = $this->AuditLog->Organisation->fetchOrg($params['org']);
|
||||
if ($org) {
|
||||
$conditions['AuditLog.org_id'] = $org['id'];
|
||||
} else {
|
||||
$conditions['AuditLog.org_id'] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($params['created'])) {
|
||||
$tempData = is_array($params['created']) ? $params['created'] : [$params['created']];
|
||||
foreach ($tempData as $k => $v) {
|
||||
$tempData[$k] = $this->AuditLog->resolveTimeDelta($v);
|
||||
}
|
||||
if (count($tempData) === 1) {
|
||||
$conditions['AuditLog.created >='] = date("Y-m-d H:i:s", $tempData[0]);
|
||||
} else {
|
||||
if ($tempData[0] < $tempData[1]) {
|
||||
$temp = $tempData[1];
|
||||
$tempData[1] = $tempData[0];
|
||||
$tempData[0] = $temp;
|
||||
}
|
||||
$conditions['AND'][] = ['AuditLog.created <=' => date("Y-m-d H:i:s", $tempData[0])];
|
||||
$conditions['AND'][] = ['AuditLog.created >=' => date("Y-m-d H:i:s", $tempData[1])];
|
||||
}
|
||||
}
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create conditions that will include just events parts that user can see.
|
||||
* @param array $event
|
||||
* @return array
|
||||
*/
|
||||
private function __createEventIndexConditions(array $event)
|
||||
{
|
||||
if ($this->_isSiteAdmin() || $event['Event']['orgc_id'] == $this->Auth->user('org_id')) {
|
||||
// Site admins and event owners can see all changes
|
||||
return ['event_id' => $event['Event']['id']];
|
||||
}
|
||||
|
||||
$event = $this->Event->fetchEvent($this->Auth->user(), [
|
||||
'eventid' => $event['Event']['id'],
|
||||
'sgReferenceOnly' => 1,
|
||||
'deleted' => [0, 1],
|
||||
'deleted_proposals' => 1,
|
||||
'noSightings' => true,
|
||||
'includeEventCorrelations' => false,
|
||||
'excludeGalaxy' => true,
|
||||
])[0];
|
||||
|
||||
$attributeIds = [];
|
||||
$objectIds = [];
|
||||
$proposalIds = array_column($event['ShadowAttribute'], 'id');
|
||||
$objectReferenceId = [];
|
||||
foreach ($event['Attribute'] as $aa) {
|
||||
$attributeIds[] = $aa['id'];
|
||||
if (!empty($aa['ShadowAttribute'])) {
|
||||
foreach ($aa['ShadowAttribute'] as $sa) {
|
||||
$proposalIds[] = $sa['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($event['Attribute']);
|
||||
foreach ($event['Object'] as $ob) {
|
||||
foreach ($ob['Attribute'] as $aa) {
|
||||
$attributeIds[] = $aa['id'];
|
||||
if (!empty($aa['ShadowAttribute'])) {
|
||||
foreach ($aa['ShadowAttribute'] as $sa) {
|
||||
$proposalIds[] = $sa['id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($ob['ObjectReference'] as $or) {
|
||||
$objectReferenceId[] = $or['id'];
|
||||
}
|
||||
$objectIds[] = $ob['id'];
|
||||
}
|
||||
unset($event['Object']);
|
||||
|
||||
$conditions = [];
|
||||
$conditions['AND']['event_id'] = $event['Event']['id'];
|
||||
$conditions['AND']['OR'][] = ['model' => 'Event'];
|
||||
|
||||
$parts = [
|
||||
'Attribute' => $attributeIds,
|
||||
'ShadowAttribute' => $proposalIds,
|
||||
'Object' => $objectIds,
|
||||
'ObjectReference' => $objectReferenceId,
|
||||
'EventReport' => array_column($event['EventReport'], 'id'),
|
||||
];
|
||||
|
||||
foreach ($parts as $model => $modelIds) {
|
||||
if (!empty($modelIds)) {
|
||||
$conditions['AND']['OR'][] = [
|
||||
'AND' => [
|
||||
'model' => $model,
|
||||
'model_id' => $modelIds,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate link to model view if exists and use has permission to access it.
|
||||
* @param array $auditLogs
|
||||
* @return array
|
||||
*/
|
||||
private function __appendModelLinks(array $auditLogs)
|
||||
{
|
||||
$models = [];
|
||||
foreach ($auditLogs as $auditLog) {
|
||||
if (isset($models[$auditLog['AuditLog']['model']])) {
|
||||
$models[$auditLog['AuditLog']['model']][] = $auditLog['AuditLog']['model_id'];
|
||||
} else {
|
||||
$models[$auditLog['AuditLog']['model']] = [$auditLog['AuditLog']['model_id']];
|
||||
}
|
||||
}
|
||||
|
||||
$eventIds = isset($models['Event']) ? $models['Event'] : [];
|
||||
|
||||
if (isset($models['ObjectReference'])) {
|
||||
$this->loadModel('ObjectReference');
|
||||
$objectReferences = $this->ObjectReference->find('list', [
|
||||
'conditions' => ['ObjectReference.id' => array_unique($models['ObjectReference'])],
|
||||
'fields' => ['ObjectReference.id', 'ObjectReference.object_id'],
|
||||
]);
|
||||
}
|
||||
|
||||
if (isset($models['Object']) || isset($objectReferences)) {
|
||||
$objectIds = array_unique(array_merge(
|
||||
isset($models['Object']) ? $models['Object'] : [],
|
||||
isset($objectReferences) ? array_values($objectReferences) : []
|
||||
));
|
||||
$this->loadModel('MispObject');
|
||||
$conditions = $this->MispObject->buildConditions($this->Auth->user());
|
||||
$conditions['Object.id'] = $objectIds;
|
||||
$objects = $this->MispObject->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'contain' => ['Event'],
|
||||
'fields' => ['Object.id', 'Object.event_id', 'Object.uuid', 'Object.deleted'],
|
||||
]);
|
||||
$objects = array_column(array_column($objects, 'Object'), null, 'id');
|
||||
$eventIds = array_merge($eventIds, array_column($objects, 'event_id'));
|
||||
}
|
||||
|
||||
if (isset($models['Attribute'])) {
|
||||
$this->loadModel('Attribute');
|
||||
$attributes = $this->Attribute->fetchAttributesSimple($this->Auth->user(), [
|
||||
'conditions' => ['Attribute.id' => array_unique($models['Attribute'])],
|
||||
'fields' => ['Attribute.id', 'Attribute.event_id', 'Attribute.uuid', 'Attribute.deleted'],
|
||||
]);
|
||||
$attributes = array_column(array_column($attributes, 'Attribute'), null, 'id');
|
||||
$eventIds = array_merge($eventIds, array_column($attributes, 'event_id'));
|
||||
}
|
||||
|
||||
if (isset($models['ShadowAttribute'])) {
|
||||
$this->loadModel('ShadowAttribute');
|
||||
$conditions = $this->ShadowAttribute->buildConditions($this->Auth->user());
|
||||
$conditions['AND'][] = ['ShadowAttribute.id' => array_unique($models['ShadowAttribute'])];
|
||||
$shadowAttributes = $this->ShadowAttribute->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['ShadowAttribute.id', 'ShadowAttribute.event_id', 'ShadowAttribute.uuid', 'ShadowAttribute.deleted'],
|
||||
'contain' => ['Event', 'Attribute'],
|
||||
]);
|
||||
$shadowAttributes = array_column(array_column($shadowAttributes, 'ShadowAttribute'), null, 'id');
|
||||
$eventIds = array_merge($eventIds, array_column($shadowAttributes, 'event_id'));
|
||||
}
|
||||
|
||||
if (!empty($eventIds)) {
|
||||
$this->loadModel('Event');
|
||||
$events = $this->Event->fetchSimpleEvents($this->Auth->user(), [
|
||||
'conditions' => ['Event.id' => array_unique($eventIds)],
|
||||
]);
|
||||
$events = array_column(array_column($events, 'Event'), null, 'id');
|
||||
}
|
||||
|
||||
$existingObjects = [];
|
||||
foreach (['User', 'Organisation', 'Galaxy', 'GalaxyCluster', 'Warninglist', 'AuthKey', 'ObjectTemplate', 'Role'] as $modelName) {
|
||||
if (isset($models[$modelName])) {
|
||||
$this->loadModel($modelName);
|
||||
$data = $this->{$modelName}->find('column', [
|
||||
'conditions' => ['id' => array_unique($models[$modelName])],
|
||||
'fields' => ['id'],
|
||||
]);
|
||||
$existingObjects[$modelName] = array_flip($data);
|
||||
}
|
||||
}
|
||||
|
||||
$links = [
|
||||
'ObjectTemplate' => 'objectTemplates',
|
||||
'AuthKey' => 'auth_keys',
|
||||
'GalaxyCluster' => 'galaxy_clusters',
|
||||
'Galaxy' => 'galaxies',
|
||||
'Organisation' => 'organisation',
|
||||
'Warninglist' => 'warninglists',
|
||||
'User' => 'admin/user',
|
||||
'Role' => 'roles',
|
||||
];
|
||||
|
||||
foreach ($auditLogs as $k => $auditLog) {
|
||||
$auditLog = $auditLog['AuditLog'];
|
||||
$modelId = (int)$auditLog['model_id'];
|
||||
$url = null;
|
||||
$eventInfo = null;
|
||||
switch ($auditLog['model']) {
|
||||
case 'Event':
|
||||
if (isset($events[$modelId])) {
|
||||
$url = '/events/view/' . $modelId;
|
||||
$eventInfo = $events[$modelId]['info'];
|
||||
}
|
||||
break;
|
||||
case 'ObjectReference':
|
||||
if (isset($objectReferences[$modelId]) && isset($objects[$objectReferences[$modelId]])) {
|
||||
$url = '/events/view/' . $objects[$objectReferences[$modelId]]['event_id'] . '/focus:' . $objects[$objectReferences[$modelId]]['uuid'];
|
||||
if ($objects[$objectReferences[$modelId]]['deleted']) {
|
||||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$objects[$objectReferences[$modelId]]['event_id']])) {
|
||||
$eventInfo = $events[$objects[$objectReferences[$modelId]]['event_id']]['info'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Object':
|
||||
if (isset($objects[$modelId])) {
|
||||
$url = '/events/view/' . $objects[$modelId]['event_id'] . '/focus:' . $objects[$modelId]['uuid'];
|
||||
if ($objects[$modelId]['deleted']) {
|
||||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$objects[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$objects[$modelId]['event_id']]['info'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'Attribute':
|
||||
if (isset($attributes[$modelId])) {
|
||||
$url = '/events/view/' . $attributes[$modelId]['event_id'] . '/focus:' . $attributes[$modelId]['uuid'];
|
||||
if ($attributes[$modelId]['deleted']) {
|
||||
$url .= '/deleted:2';
|
||||
}
|
||||
if (isset($events[$attributes[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$attributes[$modelId]['event_id']]['info'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'ShadowAttribute':
|
||||
if (isset($shadowAttributes[$modelId])) {
|
||||
$url = '/events/view/' . $shadowAttributes[$modelId]['event_id'] . '/focus:' . $shadowAttributes[$modelId]['uuid'];
|
||||
if (isset($events[$shadowAttributes[$modelId]['event_id']])) {
|
||||
$eventInfo = $events[$shadowAttributes[$modelId]['event_id']]['info'];
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (isset($existingObjects[$auditLog['model']][$modelId])) {
|
||||
$url = '/' . $links[$auditLog['model']] . '/view/' . $modelId;
|
||||
} else {
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
if ($url) {
|
||||
$auditLogs[$k]['AuditLog']['model_link'] = $this->baseurl . $url;
|
||||
}
|
||||
if ($eventInfo) {
|
||||
$auditLogs[$k]['AuditLog']['event_info'] = $eventInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return $auditLogs;
|
||||
}
|
||||
}
|
|
@ -377,6 +377,12 @@ class ACLComponent extends Component
|
|||
'testForStolenAttributes' => array(),
|
||||
'pruneUpdateLogs' => array()
|
||||
),
|
||||
'auditLogs' => [
|
||||
'admin_index' => ['perm_audit'],
|
||||
'fullChange' => ['perm_audit'],
|
||||
'eventIndex' => ['*'],
|
||||
'returnDates' => ['*'],
|
||||
],
|
||||
'modules' => array(
|
||||
'index' => array('perm_auth'),
|
||||
'queryEnrichment' => array('perm_auth'),
|
||||
|
@ -677,6 +683,7 @@ class ACLComponent extends Component
|
|||
'admin_email' => array('perm_admin'),
|
||||
'admin_filterUserIndex' => array('perm_admin'),
|
||||
'admin_index' => array('perm_admin'),
|
||||
'admin_massToggleField' => array('perm_admin'),
|
||||
'admin_monitor' => array('perm_site_admin'),
|
||||
'admin_quickEmail' => array('perm_admin'),
|
||||
'admin_view' => array('perm_admin'),
|
||||
|
|
|
@ -610,11 +610,14 @@ class RestResponseComponent extends Component
|
|||
}
|
||||
|
||||
/**
|
||||
* Detect if request comes from automatic tool, like other MISP instance or PyMISP
|
||||
* Detect if request comes from automatic tool (like other MISP instance or PyMISP) or AJAX
|
||||
* @return bool
|
||||
*/
|
||||
public function isAutomaticTool()
|
||||
{
|
||||
if ($this->Controller->request->is('ajax')) {
|
||||
return true;
|
||||
}
|
||||
$userAgent = CakeRequest::header('User-Agent');
|
||||
return $userAgent && (substr($userAgent, 0, 6) === 'PyMISP' || substr($userAgent, 0, 4) === 'MISP');
|
||||
}
|
||||
|
|
|
@ -863,6 +863,10 @@ class EventsController extends AppController
|
|||
$possibleColumns[] = 'proposals';
|
||||
}
|
||||
|
||||
if (Configure::read('MISP.showEventReportCountOnIndex')) {
|
||||
$possibleColumns[] = 'report_count';
|
||||
}
|
||||
|
||||
if (Configure::read('MISP.showDiscussionsCountOnIndex')) {
|
||||
$possibleColumns[] = 'discussion';
|
||||
}
|
||||
|
@ -906,6 +910,10 @@ class EventsController extends AppController
|
|||
$events = $this->Event->attachDiscussionsCountToEvents($user, $events);
|
||||
}
|
||||
|
||||
if (in_array('report_count', $columns, true)) {
|
||||
$events = $this->Event->EventReport->attachReportCountsToEvents($user, $events);
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
@ -1151,7 +1159,17 @@ class EventsController extends AppController
|
|||
$this->set('includeDecayScore', 0);
|
||||
}
|
||||
|
||||
$results = $this->Event->fetchEvent($this->Auth->user(), $conditions);
|
||||
// Site admin can view event as different user
|
||||
if ($this->_isSiteAdmin() && isset($this->params['named']['viewAs'])) {
|
||||
$user = $this->User->getAuthUser($this->params['named']['viewAs']);
|
||||
if (empty($user)) {
|
||||
throw new NotFoundException(__("User not found"));
|
||||
}
|
||||
} else {
|
||||
$user = $this->Auth->user();
|
||||
}
|
||||
|
||||
$results = $this->Event->fetchEvent($user, $conditions);
|
||||
if (empty($results)) {
|
||||
throw new NotFoundException(__('Invalid event'));
|
||||
}
|
||||
|
@ -1300,11 +1318,12 @@ class EventsController extends AppController
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
* @param array $event
|
||||
* @param bool $continue
|
||||
* @param int $fromEvent
|
||||
*/
|
||||
private function __viewUI($event, $continue, $fromEvent)
|
||||
private function __viewUI(array $user, $event, $continue, $fromEvent)
|
||||
{
|
||||
$this->loadModel('Taxonomy');
|
||||
$filterData = array(
|
||||
|
@ -1338,7 +1357,7 @@ class EventsController extends AppController
|
|||
// set the data for the contributors / history field
|
||||
$contributors = $this->Event->ShadowAttribute->getEventContributors($event['Event']['id']);
|
||||
$this->set('contributors', $contributors);
|
||||
if ($this->userRole['perm_publish'] && $event['Event']['orgc_id'] == $this->Auth->user('org_id')) {
|
||||
if ($user['Role']['perm_publish'] && $event['Event']['orgc_id'] == $user['org_id']) {
|
||||
$proposalStatus = false;
|
||||
if (isset($event['ShadowAttribute']) && !empty($event['ShadowAttribute'])) {
|
||||
$proposalStatus = true;
|
||||
|
@ -1482,12 +1501,12 @@ class EventsController extends AppController
|
|||
}
|
||||
unset($modificationMap);
|
||||
$this->loadModel('Sighting');
|
||||
$sightingsData = $this->Sighting->eventsStatistic([$event], $this->Auth->user());
|
||||
$sightingsData = $this->Sighting->eventsStatistic([$event], $user);
|
||||
$this->set('sightingsData', $sightingsData);
|
||||
$params = $this->Event->rearrangeEventForView($event, $filters, false, $sightingsData);
|
||||
if (!empty($filters['includeSightingdb']) && Configure::read('Plugin.Sightings_sighting_db_enable')) {
|
||||
$this->loadModel('Sightingdb');
|
||||
$event = $this->Sightingdb->attachToEvent($event, $this->Auth->user());
|
||||
$event = $this->Sightingdb->attachToEvent($event, $user);
|
||||
}
|
||||
$this->params->params['paging'] = array($this->modelClass => $params);
|
||||
$this->set('event', $event);
|
||||
|
@ -1496,10 +1515,10 @@ class EventsController extends AppController
|
|||
'Event.extends_uuid' => $event['Event']['uuid']
|
||||
)
|
||||
);
|
||||
$extensions = $this->Event->fetchSimpleEvents($this->Auth->user(), $extensionParams);
|
||||
$extensions = $this->Event->fetchSimpleEvents($user, $extensionParams);
|
||||
$this->set('extensions', $extensions);
|
||||
if (!empty($event['Event']['extends_uuid'])) {
|
||||
$extendedEvent = $this->Event->fetchSimpleEvents($this->Auth->user(), array('conditions' => array('Event.uuid' => $event['Event']['extends_uuid'])));
|
||||
$extendedEvent = $this->Event->fetchSimpleEvents($user, array('conditions' => array('Event.uuid' => $event['Event']['extends_uuid'])));
|
||||
if (empty($extendedEvent)) {
|
||||
$extendedEvent = $event['Event']['extends_uuid'];
|
||||
}
|
||||
|
@ -1509,8 +1528,8 @@ class EventsController extends AppController
|
|||
$this->loadModel('EventDelegation');
|
||||
$delegationConditions = array('EventDelegation.event_id' => $event['Event']['id']);
|
||||
if (!$this->_isSiteAdmin() && $this->userRole['perm_publish']) {
|
||||
$delegationConditions['OR'] = array('EventDelegation.org_id' => $this->Auth->user('org_id'),
|
||||
'EventDelegation.requester_org_id' => $this->Auth->user('org_id'));
|
||||
$delegationConditions['OR'] = array('EventDelegation.org_id' => $user['org_id'],
|
||||
'EventDelegation.requester_org_id' => $user['org_id']);
|
||||
}
|
||||
$this->set('delegationRequest', $this->EventDelegation->find('first', array(
|
||||
'conditions' => $delegationConditions,
|
||||
|
@ -1520,11 +1539,11 @@ class EventsController extends AppController
|
|||
}
|
||||
if (Configure::read('Plugin.Enrichment_services_enable')) {
|
||||
$this->loadModel('Module');
|
||||
$modules = $this->Module->getEnabledModules($this->Auth->user());
|
||||
$modules = $this->Module->getEnabledModules($user);
|
||||
if (is_array($modules)) {
|
||||
foreach ($modules as $k => $v) {
|
||||
if (isset($v['restrict'])) {
|
||||
if ($this->_isSiteAdmin() && $v['restrict'] != $this->Auth->user('org_id')) {
|
||||
if ($this->_isSiteAdmin() && $v['restrict'] != $user['org_id']) {
|
||||
unset($modules[$k]);
|
||||
}
|
||||
}
|
||||
|
@ -1534,7 +1553,7 @@ class EventsController extends AppController
|
|||
}
|
||||
if (Configure::read('Plugin.Cortex_services_enable')) {
|
||||
$this->loadModel('Module');
|
||||
$cortex_modules = $this->Module->getEnabledModules($this->Auth->user(), false, 'Cortex');
|
||||
$cortex_modules = $this->Module->getEnabledModules($user, false, 'Cortex');
|
||||
$this->set('cortex_modules', $cortex_modules);
|
||||
}
|
||||
$this->set('typeGroups', array_keys($this->Event->Attribute->typeGroupings));
|
||||
|
@ -1554,7 +1573,7 @@ class EventsController extends AppController
|
|||
'fields' => array('Orgc.id', 'Orgc.name')
|
||||
));
|
||||
if (!empty($filters['includeSightingdb']) && Configure::read('Plugin.Sightings_sighting_db_enable')) {
|
||||
$this->set('sightingdbs', $this->Sightingdb->getSightingdbList($this->Auth->user()));
|
||||
$this->set('sightingdbs', $this->Sightingdb->getSightingdbList($user));
|
||||
}
|
||||
$this->set('includeSightingdb', (!empty($filters['includeSightingdb']) && Configure::read('Plugin.Sightings_sighting_db_enable')));
|
||||
$this->set('relatedEventCorrelationCount', $relatedEventCorrelationCount);
|
||||
|
@ -1655,7 +1674,19 @@ class EventsController extends AppController
|
|||
} else {
|
||||
$conditions['includeServerCorrelations'] = $this->params['named']['includeServerCorrelations'];
|
||||
}
|
||||
$results = $this->Event->fetchEvent($this->Auth->user(), $conditions);
|
||||
|
||||
// Site admin can view event as different user
|
||||
if ($this->_isSiteAdmin() && isset($this->params['named']['viewAs'])) {
|
||||
$user = $this->User->getAuthUser($this->params['named']['viewAs']);
|
||||
if (empty($user)) {
|
||||
throw new NotFoundException(__("User not found"));
|
||||
}
|
||||
$this->Flash->info(__('Viewing event as %s from %s', h($user['email']), h($user['Organisation']['name'])));
|
||||
} else {
|
||||
$user = $this->Auth->user();
|
||||
}
|
||||
|
||||
$results = $this->Event->fetchEvent($user, $conditions);
|
||||
if (empty($results)) {
|
||||
throw new NotFoundException(__('Invalid event'));
|
||||
}
|
||||
|
@ -1703,7 +1734,7 @@ class EventsController extends AppController
|
|||
if ($this->_isSiteAdmin() && $event['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
|
||||
$this->Flash->info(__('You are currently logged in as a site administrator and about to edit an event not belonging to your organisation. This goes against the sharing model of MISP. Use a normal user account for day to day work.'));
|
||||
}
|
||||
$this->__viewUI($event, $continue, $fromEvent);
|
||||
$this->__viewUI($user, $event, $continue, $fromEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3280,41 +3311,40 @@ class EventsController extends AppController
|
|||
public function proposalEventIndex()
|
||||
{
|
||||
$this->loadModel('ShadowAttribute');
|
||||
$this->ShadowAttribute->recursive = -1;
|
||||
$conditions = array('ShadowAttribute.deleted' => 0);
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions[] = array('ShadowAttribute.event_org_id' => $this->Auth->user('org_id'));
|
||||
}
|
||||
$result = $this->ShadowAttribute->find('all', array(
|
||||
'fields' => array('event_id'),
|
||||
'group' => array('event_id', 'id'),
|
||||
'conditions' => $conditions
|
||||
));
|
||||
$result = $this->ShadowAttribute->find('column', [
|
||||
'fields' => ['event_id'],
|
||||
'conditions' => $conditions,
|
||||
'unique' => true,
|
||||
]);
|
||||
$this->Event->recursive = -1;
|
||||
$conditions = array();
|
||||
foreach ($result as $eventId) {
|
||||
$conditions['OR'][] = array('Event.id =' => $eventId['ShadowAttribute']['event_id']);
|
||||
}
|
||||
|
||||
if (empty($result)) {
|
||||
$conditions['OR'][] = array('Event.id =' => -1);
|
||||
$conditions = array('Event.id' => -1);
|
||||
} else {
|
||||
$conditions = array('Event.id' => $result);
|
||||
}
|
||||
$this->paginate = array(
|
||||
'fields' => array('Event.id', 'Event.org_id', 'Event.orgc_id', 'Event.publish_timestamp', 'Event.distribution', 'Event.info', 'Event.date', 'Event.published'),
|
||||
'conditions' => $conditions,
|
||||
'contain' => array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'User.email'
|
||||
)),
|
||||
'ShadowAttribute'=> array(
|
||||
'fields' => array(
|
||||
'ShadowAttribute.id', 'ShadowAttribute.org_id', 'ShadowAttribute.event_id'
|
||||
),
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.deleted' => 0
|
||||
),
|
||||
'fields' => array('Event.id', 'Event.org_id', 'Event.orgc_id', 'Event.publish_timestamp', 'Event.distribution', 'Event.info', 'Event.date', 'Event.published'),
|
||||
'conditions' => $conditions,
|
||||
'contain' => array(
|
||||
'User' => array(
|
||||
'fields' => array(
|
||||
'User.email'
|
||||
)),
|
||||
'ShadowAttribute'=> array(
|
||||
'fields' => array(
|
||||
'ShadowAttribute.id', 'ShadowAttribute.org_id', 'ShadowAttribute.event_id'
|
||||
),
|
||||
));
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.deleted' => 0
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
$events = $this->paginate();
|
||||
$orgIds = array();
|
||||
foreach ($events as $k => $event) {
|
||||
|
@ -5455,10 +5485,10 @@ class EventsController extends AppController
|
|||
$editors = array_unique($editors);
|
||||
|
||||
if ($event['Event']['timestamp'] > $timestamp && empty($editors)) {
|
||||
$message = __('<b>Warning<b>: This event view is outdated. Please reload page to see latest changes.');
|
||||
$message = __('<b>Warning</b>: This event view is outdated. Please reload page to see latest changes.');
|
||||
$this->set('class', 'alert');
|
||||
} else if ($event['Event']['timestamp'] > $timestamp) {
|
||||
$message = __('<b>Warning<b>: This event view is outdated, because is currently being edited by: %s. Please reload page to see latest changes.', h(implode(', ', $editors)));
|
||||
$message = __('<b>Warning</b>: This event view is outdated, because is currently being edited by: %s. Please reload page to see latest changes.', h(implode(', ', $editors)));
|
||||
$this->set('class', 'alert');
|
||||
} else if (empty($editors)) {
|
||||
return new CakeResponse(['status' => 204]);
|
||||
|
|
|
@ -118,6 +118,8 @@ class LogsController extends AppController
|
|||
'deleted_proposals' => 1,
|
||||
'noSightings' => true,
|
||||
'noEventReports' => true,
|
||||
'includeEventCorrelations' => false,
|
||||
'excludeGalaxy' => true,
|
||||
));
|
||||
if (empty($event)) {
|
||||
throw new NotFoundException('Invalid event.');
|
||||
|
@ -125,7 +127,7 @@ class LogsController extends AppController
|
|||
$event = $event[0];
|
||||
$attribute_ids = array();
|
||||
$object_ids = array();
|
||||
$proposal_ids = array();
|
||||
$proposal_ids = array_column($event['ShadowAttribute'], 'id');;
|
||||
if (!empty($event['Attribute'])) {
|
||||
foreach ($event['Attribute'] as $aa) {
|
||||
$attribute_ids[] = $aa['id'];
|
||||
|
|
|
@ -159,6 +159,7 @@ class OrganisationsController extends AppController
|
|||
}
|
||||
$countries = array_merge(['' => __('Not specified')], $this->_arrayToValuesIndexArray($this->Organisation->getCountries()));
|
||||
$this->set('countries', $countries);
|
||||
$this->set('action', 'add');
|
||||
}
|
||||
|
||||
public function admin_edit($id)
|
||||
|
@ -183,7 +184,7 @@ class OrganisationsController extends AppController
|
|||
$this->request->data['Organisation'] = $this->request->data;
|
||||
}
|
||||
$existingOrg = $this->Organisation->find('first', array('conditions' => array('Organisation.id' => $id)));
|
||||
$changeFields = array('name', 'type', 'nationality', 'sector', 'contacts', 'description', 'local', 'uuid');
|
||||
$changeFields = array('name', 'type', 'nationality', 'sector', 'contacts', 'description', 'local', 'uuid', 'restricted_to_domain');
|
||||
$temp = array('Organisation' => array());
|
||||
foreach ($changeFields as $field) {
|
||||
if (isset($this->request->data['Organisation'][$field])) {
|
||||
|
@ -245,6 +246,8 @@ class OrganisationsController extends AppController
|
|||
$this->request->data['Organisation']['restricted_to_domain'] = implode("\n", $this->request->data['Organisation']['restricted_to_domain']);
|
||||
}
|
||||
$this->set('id', $id);
|
||||
$this->set('action', 'edit');
|
||||
$this->render('admin_add');
|
||||
}
|
||||
|
||||
public function admin_delete($id)
|
||||
|
|
|
@ -455,14 +455,14 @@ class ServersController extends AppController
|
|||
$this->redirect(array('controller' => 'servers', 'action' => 'index'));
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
if (empty(Configure::read('MISP.host_org_id'))) {
|
||||
$this->request->data['Server']['internal'] = 0;
|
||||
}
|
||||
if ($this->_isRest()) {
|
||||
if (!isset($this->request->data['Server'])) {
|
||||
$this->request->data = array('Server' => $this->request->data);
|
||||
}
|
||||
}
|
||||
if (empty(Configure::read('MISP.host_org_id'))) {
|
||||
$this->request->data['Server']['internal'] = 0;
|
||||
}
|
||||
if (isset($this->request->data['Server']['json'])) {
|
||||
$json = json_decode($this->request->data['Server']['json'], true);
|
||||
} else {
|
||||
|
|
|
@ -28,6 +28,8 @@ class UsersController extends AppController
|
|||
|
||||
public $helpers = array('Js' => array('Jquery'));
|
||||
|
||||
public $toggleableFields = ['disabled', 'autoalert'];
|
||||
|
||||
public function beforeFilter()
|
||||
{
|
||||
parent::beforeFilter();
|
||||
|
@ -473,11 +475,6 @@ class UsersController extends AppController
|
|||
}
|
||||
$this->set('users', $users);
|
||||
}
|
||||
if ($this->request->is('ajax')) {
|
||||
$this->autoRender = false;
|
||||
$this->layout = false;
|
||||
$this->render('ajax/admin_index');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1095,6 +1092,54 @@ class UsersController extends AppController
|
|||
$this->redirect(array('action' => 'index'));
|
||||
}
|
||||
|
||||
public function admin_massToggleField($fieldName, $enabled)
|
||||
{
|
||||
if (!in_array($fieldName, $this->toggleableFields)) {
|
||||
throw new MethodNotAllowedException(__('The field `%s` cannot be toggled', $fieldName));
|
||||
}
|
||||
if (!$this->_isAdmin()) {
|
||||
throw new UnauthorizedException(__('Administrators only'));
|
||||
}
|
||||
if ($this->request->is('post') || $this->request->is('put')) {
|
||||
$jsonIds = $this->request->data['User']['user_ids'];
|
||||
$ids = $this->User->jsonDecode($jsonIds);
|
||||
$conditions = ['User.id' => $ids];
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions['User.org_id'] = $this->Auth->user('org_id');
|
||||
}
|
||||
$users = $this->User->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1
|
||||
]);
|
||||
if (empty($users)) {
|
||||
throw new NotFoundException(__('Invalid users'));
|
||||
}
|
||||
$count = 0;
|
||||
foreach ($users as $user) {
|
||||
if ($user['User'][$fieldName] != $enabled) {
|
||||
$this->User->id = $user['User']['id'];
|
||||
$this->User->saveField($fieldName, $enabled);
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
if ($count > 0) {
|
||||
$message = __('%s users got their field `%s` %s', $count, $fieldName, $enabled ? __('enabled') : __('disabled'));
|
||||
} else {
|
||||
$message = __('All users have already their field `%s` %s', $fieldName, $enabled ? __('enabled') : __('disabled'));
|
||||
}
|
||||
if ($this->_isRest()) {
|
||||
return $this->RestResponse->saveSuccessResponse('User', 'admin_massToggleField', 'selected', $this->response->type(), $message);
|
||||
} else {
|
||||
if ($count > 0) {
|
||||
$this->Flash->success($message);
|
||||
} else {
|
||||
$this->Flash->info($message);
|
||||
}
|
||||
$this->redirect('/admin/users/index');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function updateLoginTime()
|
||||
{
|
||||
if (!$this->request->is('post')) {
|
||||
|
@ -1245,9 +1290,9 @@ class UsersController extends AppController
|
|||
),
|
||||
'recursive' => -1
|
||||
));
|
||||
$lastUserLogin = $user['User']['last_login'];
|
||||
unset($user['User']['password']);
|
||||
$this->User->updateLoginTimes($user['User']);
|
||||
$lastUserLogin = $user['User']['last_login'];
|
||||
$this->User->Behaviors->enable('SysLogLogable.SysLogLogable');
|
||||
if ($lastUserLogin) {
|
||||
$readableDatetime = (new DateTime())->setTimestamp($lastUserLogin)->format('D, d M y H:i:s O'); // RFC822
|
||||
|
@ -1813,14 +1858,14 @@ class UsersController extends AppController
|
|||
{
|
||||
// set all of the data up for the heatmaps
|
||||
$params = array(
|
||||
'fields' => array('name'),
|
||||
'fields' => array('id', 'name'),
|
||||
'recursive' => -1,
|
||||
'conditions' => array()
|
||||
);
|
||||
if (!$this->_isSiteAdmin() && !empty(Configure::read('Security.hide_organisation_index_from_users'))) {
|
||||
$params['conditions'] = array('Organisation.id' => $this->Auth->user('org_id'));
|
||||
}
|
||||
$orgs = $this->User->Organisation->find('all', $params);
|
||||
$orgs = $this->User->Organisation->find('list', $params);
|
||||
|
||||
$local_orgs_params = $params;
|
||||
$local_orgs_params['conditions']['Organisation.local'] = 1;
|
||||
|
@ -1848,7 +1893,7 @@ class UsersController extends AppController
|
|||
$stats['correlation_count'] = $this->Correlation->find('count', array('recursive' => -1));
|
||||
$stats['correlation_count'] = $stats['correlation_count'] / 2;
|
||||
|
||||
$stats['proposal_count'] = $this->User->Event->ShadowAttribute->find('count', array('recursive' => -1));
|
||||
$stats['proposal_count'] = $this->User->Event->ShadowAttribute->find('count', array('recursive' => -1, 'conditions' => array('deleted' => 0)));
|
||||
|
||||
$stats['user_count'] = $this->User->find('count', array('recursive' => -1));
|
||||
$stats['user_count_pgp'] = $this->User->find('count', array('recursive' => -1, 'conditions' => array('User.gpgkey !=' => '')));
|
||||
|
@ -1869,16 +1914,17 @@ class UsersController extends AppController
|
|||
'stats' => $stats
|
||||
);
|
||||
return $this->RestResponse->viewData($data, $this->response->type());
|
||||
} else {
|
||||
$this->set('stats', $stats);
|
||||
$this->set('orgs', $orgs);
|
||||
$this->set('start', strtotime(date('Y-m-d H:i:s') . ' -5 months'));
|
||||
$this->set('end', strtotime(date('Y-m-d H:i:s')));
|
||||
$this->set('startDateCal', $year . ', ' . $month . ', 01');
|
||||
$range = '[5, 10, 50, 100]';
|
||||
$this->set('range', $range);
|
||||
$this->render('statistics_data');
|
||||
}
|
||||
|
||||
$this->set('stats', $stats);
|
||||
$this->set('orgs', $orgs);
|
||||
$this->set('start', strtotime(date('Y-m-d H:i:s') . ' -5 months'));
|
||||
$this->set('end', strtotime(date('Y-m-d H:i:s')));
|
||||
$this->set('startDateCal', $year . ', ' . $month . ', 01');
|
||||
$range = '[5, 10, 50, 100]';
|
||||
$this->set('range', $range);
|
||||
$this->set('activityUrl', $this->baseurl . (Configure::read('MISP.log_new_audit') ? '/audit_logs' : '/logs') . '/returnDates');
|
||||
$this->render('statistics_data');
|
||||
}
|
||||
|
||||
private function __statisticsSightings($params = array())
|
||||
|
|
|
@ -30,7 +30,7 @@ class UsageDataWidget
|
|||
$this->Correlation = ClassRegistry::init('Correlation');
|
||||
$correlationsCount = $this->Correlation->find('count', array('recursive' => -1)) / 2;
|
||||
|
||||
$proposalsCount = $this->Event->ShadowAttribute->find('count', array('recursive' => -1));
|
||||
$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 !=' => '')));
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
<?php
|
||||
|
||||
App::uses('JsonExport', 'Export');
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
|
||||
class YaraExport
|
||||
{
|
||||
private $__script_path = APP . 'files/scripts/yara/yaraexport.py';
|
||||
|
@ -13,6 +11,7 @@ class YaraExport
|
|||
private $__MAX_n_attributes = 15000;
|
||||
private $__yara_file_gen = null;
|
||||
private $__yara_file_asis = null;
|
||||
/** @var null|File */
|
||||
private $__curr_input_file = null;
|
||||
private $__scope = false;
|
||||
private $__curr_input_is_empty = true;
|
||||
|
@ -73,7 +72,13 @@ class YaraExport
|
|||
$this->separator(); // calling separator since returning '' will prevent it
|
||||
}
|
||||
$jsonData = $this->__JsonExporter->handler($data, $options);
|
||||
$this->__curr_input_file->append($jsonData);
|
||||
if ($jsonData instanceof Generator) {
|
||||
foreach ($jsonData as $part) {
|
||||
$this->__curr_input_file->append($part);
|
||||
}
|
||||
} else {
|
||||
$this->__curr_input_file->append($jsonData);
|
||||
}
|
||||
$this->__curr_input_is_empty = false;
|
||||
}
|
||||
$this->__n_attributes += $attr_count;
|
||||
|
|
|
@ -125,6 +125,12 @@ class SecurityAudit
|
|||
__('Passing user information to response headers is disabled. This can be useful for logging user info at the reverse proxy level. You can enable it by setting `Security.username_in_response_header` to `true`.'),
|
||||
];
|
||||
}
|
||||
if (!Configure::read('MISP.log_new_audit')) {
|
||||
$output['Logging'][] = [
|
||||
'hint',
|
||||
__('New audit log stores more information, like used authkey ID or request ID that can help when analysing or correlating audit logs.'),
|
||||
];
|
||||
}
|
||||
|
||||
if (empty(Configure::read('MISP.attachment_scan_module'))) {
|
||||
$output['Attachment scanning'][] = ['hint', __('No module for scanning attachments for viruses is currently defined.')];
|
||||
|
|
|
@ -6,6 +6,7 @@ class AdminSetting extends AppModel
|
|||
public $useTable = 'admin_settings';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -9,6 +9,7 @@ class Allowedlist extends AppModel
|
|||
public $displayField = 'name';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Trim',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Role',
|
||||
|
|
|
@ -89,7 +89,8 @@ class AppModel extends Model
|
|||
45 => false, 46 => false, 47 => false, 48 => false, 49 => false, 50 => false,
|
||||
51 => false, 52 => false, 53 => false, 54 => false, 55 => false, 56 => false,
|
||||
57 => false, 58 => false, 59 => false, 60 => false, 61 => false, 62 => false,
|
||||
63 => true, 64 => false, 65 => false, 66 => false, 67 => false, 68 => false
|
||||
63 => true, 64 => false, 65 => false, 66 => false, 67 => false, 68 => false,
|
||||
69 => false,
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1578,6 +1579,27 @@ class AppModel extends Model
|
|||
case 68:
|
||||
$sqlArray[] = "ALTER TABLE `correlation_exclusions` ADD `comment` text DEFAULT NULL;";
|
||||
break;
|
||||
case 69:
|
||||
$sqlArray[] = "CREATE TABLE IF NOT EXISTS `audit_logs` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`created` datetime NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`org_id` int(11) NOT NULL,
|
||||
`authkey_id` int(11) DEFAULT NULL,
|
||||
`ip` varbinary(16) DEFAULT NULL,
|
||||
`request_type` tinyint NOT NULL,
|
||||
`request_id` varchar(255) DEFAULT NULL,
|
||||
`action` varchar(20) NOT NULL,
|
||||
`model` varchar(80) NOT NULL,
|
||||
`model_id` int(11) NOT NULL,
|
||||
`model_title` text DEFAULT NULL,
|
||||
`event_id` int(11) NULL,
|
||||
`change` blob,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `event_id` (`event_id`),
|
||||
INDEX `model_id` (`model_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;";
|
||||
break;
|
||||
case 'fixNonEmptySharingGroupID':
|
||||
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
|
|
|
@ -23,6 +23,7 @@ class Attribute extends AppModel
|
|||
public $name = 'Attribute'; // TODO general
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -7,7 +7,7 @@ App::uses('AppModel', 'Model');
|
|||
*/
|
||||
class AttributeTag extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $validate = array(
|
||||
'attribute_id' => array(
|
||||
|
@ -296,8 +296,13 @@ class AttributeTag extends AppModel
|
|||
return $allTags;
|
||||
}
|
||||
|
||||
// find all galaxies that belong to a list of attributes (contains in the same event)
|
||||
public function getAttributesClusters(array $attributes)
|
||||
/**
|
||||
* Find all galaxies that belong to a list of attributes (contains in the same event)
|
||||
* @param array $user
|
||||
* @param array $attributes
|
||||
* @return array
|
||||
*/
|
||||
public function getAttributesClusters(array $user, array $attributes)
|
||||
{
|
||||
if (empty($attributes)) {
|
||||
return array();
|
||||
|
|
|
@ -0,0 +1,366 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
/**
|
||||
* @property Event $Event
|
||||
* @property User $User
|
||||
* @property Organisation $Organisation
|
||||
*/
|
||||
class AuditLog extends AppModel
|
||||
{
|
||||
const BROTLI_HEADER = "\xce\xb2\xcf\x81";
|
||||
const BROTLI_MIN_LENGTH = 200;
|
||||
|
||||
const ACTION_ADD = 'add',
|
||||
ACTION_EDIT = 'edit',
|
||||
ACTION_SOFT_DELETE = 'soft_delete',
|
||||
ACTION_DELETE = 'delete',
|
||||
ACTION_UNDELETE = 'undelete',
|
||||
ACTION_TAG = 'tag',
|
||||
ACTION_TAG_LOCAL = 'tag_local',
|
||||
ACTION_REMOVE_TAG = 'remove_tag',
|
||||
ACTION_REMOVE_TAG_LOCAL = 'remove_local_tag',
|
||||
ACTION_GALAXY = 'galaxy',
|
||||
ACTION_GALAXY_LOCAL = 'galaxy_local',
|
||||
ACTION_REMOVE_GALAXY = 'remove_galaxy',
|
||||
ACTION_REMOVE_GALAXY_LOCAL = 'remove_local_galaxy',
|
||||
ACTION_PUBLISH = 'publish',
|
||||
ACTION_PUBLISH_SIGHTINGS = 'publish_sightings';
|
||||
|
||||
const REQUEST_TYPE_DEFAULT = 0,
|
||||
REQUEST_TYPE_API = 1,
|
||||
REQUEST_TYPE_CLI = 2;
|
||||
|
||||
public $actsAs = [
|
||||
'Containable',
|
||||
];
|
||||
|
||||
/** @var array|null */
|
||||
private $user = null;
|
||||
|
||||
/** @var bool */
|
||||
private $compressionEnabled;
|
||||
|
||||
/**
|
||||
* Null when not defined, false when not enabled
|
||||
* @var Syslog|null|false
|
||||
*/
|
||||
private $syslog;
|
||||
|
||||
public $compressionStats = [
|
||||
'compressed' => 0,
|
||||
'bytes_compressed' => 0,
|
||||
'bytes_uncompressed' => 0,
|
||||
];
|
||||
|
||||
public $belongsTo = [
|
||||
'User' => [
|
||||
'className' => 'User',
|
||||
'foreignKey' => 'user_id',
|
||||
],
|
||||
'Event' => [
|
||||
'className' => 'Event',
|
||||
'foreignKey' => 'event_id',
|
||||
],
|
||||
'Organisation' => [
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id',
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->compressionEnabled = Configure::read('MISP.log_new_audit_compress') && function_exists('brotli_compress');
|
||||
}
|
||||
|
||||
public function afterFind($results, $primary = false)
|
||||
{
|
||||
foreach ($results as $key => $result) {
|
||||
if (isset($result['AuditLog']['ip'])) {
|
||||
$results[$key]['AuditLog']['ip'] = inet_ntop($result['AuditLog']['ip']);
|
||||
}
|
||||
if (isset($result['AuditLog']['change']) && $result['AuditLog']['change']) {
|
||||
$results[$key]['AuditLog']['change'] = $this->decodeChange($result['AuditLog']['change']);
|
||||
}
|
||||
if (isset($result['AuditLog']['action']) && isset($result['AuditLog']['model']) && isset($result['AuditLog']['model_id'])) {
|
||||
$results[$key]['AuditLog']['title'] = $this->generateUserFriendlyTitle($result['AuditLog']);
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $auditLog
|
||||
* @return string
|
||||
*/
|
||||
private function generateUserFriendlyTitle(array $auditLog)
|
||||
{
|
||||
if (in_array($auditLog['action'], [self::ACTION_TAG, self::ACTION_TAG_LOCAL, self::ACTION_REMOVE_TAG, self::ACTION_REMOVE_TAG_LOCAL], true)) {
|
||||
$attached = ($auditLog['action'] === self::ACTION_TAG || $auditLog['action'] === self::ACTION_TAG_LOCAL);
|
||||
$local = ($auditLog['action'] === self::ACTION_TAG_LOCAL || $auditLog['action'] === self::ACTION_REMOVE_TAG_LOCAL) ? 'local' : 'global';
|
||||
if ($attached) {
|
||||
return __('Attached %s tag "%s" to %s #%s', $local, $auditLog['model_title'], strtolower($auditLog['model']), $auditLog['model_id']);
|
||||
} else {
|
||||
return __('Detached %s tag "%s" from %s #%s', $local, $auditLog['model_title'], strtolower($auditLog['model']), $auditLog['model_id']);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($auditLog['action'], [self::ACTION_GALAXY, self::ACTION_GALAXY_LOCAL, self::ACTION_REMOVE_GALAXY, self::ACTION_REMOVE_GALAXY_LOCAL], true)) {
|
||||
$attached = ($auditLog['action'] === self::ACTION_GALAXY || $auditLog['action'] === self::ACTION_GALAXY_LOCAL);
|
||||
$local = ($auditLog['action'] === self::ACTION_GALAXY_LOCAL || $auditLog['action'] === self::ACTION_REMOVE_GALAXY_LOCAL) ? 'local' : 'global';
|
||||
if ($attached) {
|
||||
return __('Attached %s galaxy cluster "%s" to %s #%s', $local, $auditLog['model_title'], strtolower($auditLog['model']), $auditLog['model_id']);
|
||||
} else {
|
||||
return __('Detached %s galaxy cluster "%s" from %s #%s', $local, $auditLog['model_title'], strtolower($auditLog['model']), $auditLog['model_id']);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array($auditLog['model'], ['Attribute', 'Object', 'ShadowAttribute'], true)) {
|
||||
$modelName = $auditLog['model'] === 'ShadowAttribute' ? 'Proposal' : $auditLog['model'];
|
||||
$title = __('%s from Event #%s', $modelName, $auditLog['event_id']);
|
||||
} else {
|
||||
$title = "{$auditLog['model']} #{$auditLog['model_id']}";
|
||||
}
|
||||
if (isset($auditLog['model_title']) && $auditLog['model_title']) {
|
||||
$title .= ": {$auditLog['model_title']}";
|
||||
}
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $change
|
||||
* @return array|string
|
||||
* @throws JsonException
|
||||
*/
|
||||
private function decodeChange($change)
|
||||
{
|
||||
if (substr($change, 0, 4) === self::BROTLI_HEADER) {
|
||||
$this->compressionStats['compressed']++;
|
||||
if (function_exists('brotli_uncompress')) {
|
||||
$this->compressionStats['bytes_compressed'] += strlen($change);
|
||||
$change = brotli_uncompress(substr($change, 4));
|
||||
$this->compressionStats['bytes_uncompressed'] += strlen($change);
|
||||
if ($change === false) {
|
||||
return 'Compressed';
|
||||
}
|
||||
} else {
|
||||
return 'Compressed';
|
||||
}
|
||||
}
|
||||
return $this->jsonDecode($change);
|
||||
}
|
||||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
if (isset($this->data['AuditLog']['change']) && !is_array($this->data['AuditLog']['change'])) {
|
||||
$this->invalidate('change', 'Change field must be array');
|
||||
}
|
||||
}
|
||||
|
||||
public function beforeSave($options = array())
|
||||
{
|
||||
if (!isset($this->data['AuditLog']['ip']) && Configure::read('MISP.log_client_ip')) {
|
||||
$ipHeader = Configure::read('MISP.log_client_ip_header') ?: 'REMOTE_ADDR';
|
||||
if (isset($_SERVER[$ipHeader])) {
|
||||
$this->data['AuditLog']['ip'] = inet_pton($_SERVER[$ipHeader]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($this->data['AuditLog']['user_id'])) {
|
||||
$this->data['AuditLog']['user_id'] = $this->userInfo()['id'];
|
||||
}
|
||||
|
||||
if (!isset($this->data['AuditLog']['org_id'])) {
|
||||
$this->data['AuditLog']['org_id'] = $this->userInfo()['org_id'];
|
||||
}
|
||||
|
||||
if (!isset($this->data['AuditLog']['request_type'])) {
|
||||
$this->data['AuditLog']['request_type'] = $this->userInfo()['request_type'];
|
||||
}
|
||||
|
||||
if (!isset($this->data['AuditLog']['authkey_id'])) {
|
||||
$this->data['AuditLog']['authkey_id'] = $this->userInfo()['authkey_id'];
|
||||
}
|
||||
|
||||
if (!isset($this->data['AuditLog']['request_id'] ) && isset($_SERVER['HTTP_X_REQUEST_ID'])) {
|
||||
$this->data['AuditLog']['request_id'] = $_SERVER['HTTP_X_REQUEST_ID'];
|
||||
}
|
||||
|
||||
// Truncate request_id
|
||||
if (isset($this->data['AuditLog']['request_id']) && strlen($this->data['AuditLog']['request_id']) > 255) {
|
||||
$this->data['AuditLog']['request_id'] = substr($this->data['AuditLog']['request_id'], 0, 255);
|
||||
}
|
||||
|
||||
// Truncate model title
|
||||
if (isset($this->data['AuditLog']['model_title']) && mb_strlen($this->data['AuditLog']['model_title']) > 255) {
|
||||
$this->data['AuditLog']['model_title'] = mb_substr($this->data['AuditLog']['model_title'], 0, 252) . '...';
|
||||
}
|
||||
|
||||
$this->logData($this->data);
|
||||
|
||||
if (isset($this->data['AuditLog']['change'])) {
|
||||
$change = json_encode($this->data['AuditLog']['change'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if ($this->compressionEnabled && strlen($change) >= self::BROTLI_MIN_LENGTH) {
|
||||
$change = self::BROTLI_HEADER . brotli_compress($change, 4, BROTLI_TEXT);
|
||||
}
|
||||
$this->data['AuditLog']['change'] = $change;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
private function logData(array $data)
|
||||
{
|
||||
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_audit_notifications_enable')) {
|
||||
$pubSubTool = $this->getPubSubTool();
|
||||
$pubSubTool->publish($data, 'audit', 'log');
|
||||
}
|
||||
|
||||
$this->publishKafkaNotification('audit', $data, 'log');
|
||||
|
||||
if (Configure::read('Plugin.ElasticSearch_logging_enable')) {
|
||||
// send off our logs to distributed /dev/null
|
||||
$logIndex = Configure::read("Plugin.ElasticSearch_log_index");
|
||||
$elasticSearchClient = $this->getElasticSearchTool();
|
||||
$elasticSearchClient->pushDocument($logIndex, "log", $data);
|
||||
}
|
||||
|
||||
// write to syslogd as well if enabled
|
||||
if ($this->syslog === null) {
|
||||
if (Configure::read('Security.syslog')) {
|
||||
$options = [];
|
||||
$syslogToStdErr = Configure::read('Security.syslog_to_stderr');
|
||||
if ($syslogToStdErr !== null) {
|
||||
$options['to_stderr'] = $syslogToStdErr;
|
||||
}
|
||||
$syslogIdent = Configure::read('Security.syslog_ident');
|
||||
if ($syslogIdent) {
|
||||
$options['ident'] = $syslogIdent;
|
||||
}
|
||||
$this->syslog = new SysLog($options);
|
||||
} else {
|
||||
$this->syslog = false;
|
||||
}
|
||||
}
|
||||
if ($this->syslog) {
|
||||
$entry = $data['AuditLog']['action'];
|
||||
$title = $this->generateUserFriendlyTitle($data['AuditLog']);
|
||||
if ($title) {
|
||||
$entry .= " -- $title";
|
||||
}
|
||||
$this->syslog->write('info', $entry);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function userInfo()
|
||||
{
|
||||
if ($this->user !== null) {
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
$this->user = ['id' => 0, 'org_id' => 0, 'authkey_id' => 0, 'request_type' => self::REQUEST_TYPE_DEFAULT];
|
||||
|
||||
$isShell = defined('CAKEPHP_SHELL') && CAKEPHP_SHELL;
|
||||
if ($isShell) {
|
||||
// do not start session for shell commands and fetch user info from configuration
|
||||
$this->user['request_type'] = self::REQUEST_TYPE_CLI;
|
||||
$currentUserId = Configure::read('CurrentUserId');
|
||||
if (!empty($currentUserId)) {
|
||||
$this->user['id'] = $currentUserId;
|
||||
$userFromDb = $this->User->find('first', [
|
||||
'conditions' => ['User.id' => $currentUserId],
|
||||
'fields' => ['User.org_id'],
|
||||
]);
|
||||
$this->user['org_id'] = $userFromDb['User']['org_id'];
|
||||
}
|
||||
} else {
|
||||
App::uses('AuthComponent', 'Controller/Component');
|
||||
$authUser = AuthComponent::user();
|
||||
if (!empty($authUser)) {
|
||||
$this->user['id'] = $authUser['id'];
|
||||
$this->user['org_id'] = $authUser['org_id'];
|
||||
if (isset($authUser['logged_by_authkey']) && $authUser['logged_by_authkey']) {
|
||||
$this->user['request_type'] = self::REQUEST_TYPE_API;
|
||||
}
|
||||
if (isset($authUser['authkey_id'])) {
|
||||
$this->user['authkey_id'] = $authUser['authkey_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
public function insert(array $data)
|
||||
{
|
||||
try {
|
||||
$this->create();
|
||||
} catch (Exception $e) {
|
||||
return; // Table is missing when updating, so this is intentional
|
||||
}
|
||||
if ($this->save($data) === false) {
|
||||
throw new Exception($this->validationErrors);
|
||||
}
|
||||
}
|
||||
|
||||
public function recompress()
|
||||
{
|
||||
$changes = $this->find('all', [
|
||||
'fields' => ['AuditLog.id', 'AuditLog.change'],
|
||||
'recursive' => -1,
|
||||
'conditions' => ['length(AuditLog.change) >=' => self::BROTLI_MIN_LENGTH],
|
||||
]);
|
||||
foreach ($changes as $change) {
|
||||
$this->save($change, true, ['id', 'change']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|int $org
|
||||
* @return array
|
||||
*/
|
||||
public function returnDates($org = 'all')
|
||||
{
|
||||
$conditions = [];
|
||||
if ($org !== 'all') {
|
||||
$org = $this->Organisation->fetchOrg($org);
|
||||
if (empty($org)) {
|
||||
throw new NotFoundException('Invalid organisation.');
|
||||
}
|
||||
$conditions['org_id'] = $org['id'];
|
||||
}
|
||||
|
||||
$dataSource = ConnectionManager::getDataSource('default')->config['datasource'];
|
||||
if ($dataSource === 'Database/Mysql' || $dataSource === 'Database/MysqlObserver') {
|
||||
$validDates = $this->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['DISTINCT UNIX_TIMESTAMP(DATE(created)) AS Date', 'count(id) AS count'],
|
||||
'conditions' => $conditions,
|
||||
'group' => ['Date'],
|
||||
'order' => ['Date'],
|
||||
]);
|
||||
} elseif ($dataSource === 'Database/Postgres') {
|
||||
if (!empty($conditions['org_id'])) {
|
||||
$condOrg = 'WHERE org_id = "' . $conditions['org_id'] . '"';
|
||||
} else {
|
||||
$condOrg = '';
|
||||
}
|
||||
$sql = 'SELECT DISTINCT EXTRACT(EPOCH FROM CAST(created AS DATE)) AS "Date", COUNT(id) AS count
|
||||
FROM audit_logs
|
||||
' . $condOrg . '
|
||||
GROUP BY "Date" ORDER BY "Date"';
|
||||
$validDates = $this->query($sql);
|
||||
}
|
||||
$data = [];
|
||||
foreach ($validDates as $k => $date) {
|
||||
$data[(int)$date[0]['Date']] = (int)$date[0]['count'];
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ class AuthKey extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
<?php
|
||||
App::uses('AuditLog', 'Model');
|
||||
|
||||
class AuditLogBehavior extends ModelBehavior
|
||||
{
|
||||
/** @var array */
|
||||
private $config;
|
||||
|
||||
/** @var array|null */
|
||||
private $old;
|
||||
|
||||
/** @var AuditLog|null */
|
||||
private $AuditLog;
|
||||
|
||||
/** @var bool */
|
||||
private $enabled;
|
||||
|
||||
private $skipFields = [
|
||||
'id' => true,
|
||||
'lastpushedid' => true,
|
||||
'timestamp' => true,
|
||||
'revision' => true,
|
||||
'modified' => true,
|
||||
'date_modified' => true, // User
|
||||
'current_login' => true, // User
|
||||
'last_login' => true, // User
|
||||
'newsread' => true, // User
|
||||
'proposal_email_lock' => true, // Event
|
||||
'warninglist_entry_count' => true, // Warninglist
|
||||
];
|
||||
|
||||
private $modelInfo = [
|
||||
'Event' => 'info',
|
||||
'User' => 'email',
|
||||
'Object' => 'name',
|
||||
'EventReport' => 'name',
|
||||
'Server' => 'name',
|
||||
'Feed' => 'name',
|
||||
'Role' => 'name',
|
||||
'SharingGroup' => 'name',
|
||||
'Tag' => 'name',
|
||||
'TagCollection' => 'name',
|
||||
'Taxonomy' => 'namespace',
|
||||
'Organisation' => 'name',
|
||||
'AdminSetting' => 'setting',
|
||||
'UserSetting' => 'setting',
|
||||
'Galaxy' => 'name',
|
||||
'GalaxyCluster' => 'value',
|
||||
'Warninglist' => 'name',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->enabled = Configure::read('MISP.log_new_audit');
|
||||
}
|
||||
|
||||
public function setup(Model $model, $config = [])
|
||||
{
|
||||
$this->config = $config;
|
||||
// Generate model info for attribute and proposals
|
||||
$attributeInfo = function (array $new, array $old) {
|
||||
$category = isset($new['category']) ? $new['category'] : $old['category'];
|
||||
$type = isset($new['type']) ? $new['type'] : $old['type'];
|
||||
$value1 = trim(isset($new['value1']) ? $new['value1'] : $old['value1']);
|
||||
$value2 = trim(isset($new['value2']) ? $new['value2'] : $old['value2']);
|
||||
$value = $value1 . (empty($value2) ? '' : '|' . $value2);
|
||||
return "$category/$type $value";
|
||||
};
|
||||
$this->modelInfo['Attribute'] = $attributeInfo;
|
||||
$this->modelInfo['ShadowAttribute'] = $attributeInfo;
|
||||
$this->modelInfo['AuthKey'] = function (array $new, array $old) {
|
||||
$start = isset($new['authkey_start']) ? $new['authkey_start'] : $old['authkey_start'];
|
||||
$end = isset($new['authkey_end']) ? $new['authkey_end'] : $old['authkey_end'];
|
||||
return "$start********************************$end";
|
||||
};
|
||||
}
|
||||
|
||||
public function beforeSave(Model $model, $options = [])
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return true;
|
||||
}
|
||||
if ($model->id) {
|
||||
$this->old = $model->find('first', [
|
||||
'conditions' => [$model->alias . '.' . $model->primaryKey => $model->id],
|
||||
'recursive' => -1,
|
||||
'callbacks' => false,
|
||||
]);
|
||||
} else {
|
||||
$this->old = null;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function afterSave(Model $model, $created, $options = [])
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($model->id) {
|
||||
$id = $model->id;
|
||||
} else if ($model->insertId) {
|
||||
$id = $model->insertId;
|
||||
} else {
|
||||
$id = null;
|
||||
}
|
||||
|
||||
if ($created) {
|
||||
$action = AuditLog::ACTION_ADD;
|
||||
} else {
|
||||
$action = AuditLog::ACTION_EDIT;
|
||||
if (isset($model->data[$model->alias]['deleted'])) {
|
||||
if ($model->data[$model->alias]['deleted']) {
|
||||
$action = AuditLog::ACTION_SOFT_DELETE;
|
||||
} else if (!$model->data[$model->alias]['deleted'] && $this->old[$model->alias]['deleted']) {
|
||||
$action = AuditLog::ACTION_UNDELETE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$changedFields = $this->changedFields($model, isset($options['fieldList']) ? $options['fieldList'] : null);
|
||||
if (empty($changedFields)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($model->name === 'Event') {
|
||||
$eventId = $id;
|
||||
} else if (isset($model->data[$model->alias]['event_id'])) {
|
||||
$eventId = $model->data[$model->alias]['event_id'];
|
||||
} else if (isset($this->old[$model->alias]['event_id'])) {
|
||||
$eventId = $this->old[$model->alias]['event_id'];
|
||||
} else {
|
||||
$eventId = null;
|
||||
}
|
||||
|
||||
$modelTitle = null;
|
||||
if (isset($this->modelInfo[$model->name])) {
|
||||
$modelTitleField = $this->modelInfo[$model->name];
|
||||
if (is_callable($modelTitleField)) {
|
||||
$modelTitle = $modelTitleField($model->data[$model->alias], isset($this->old[$model->alias]) ? $this->old[$model->alias] : []);
|
||||
} else if (isset($model->data[$model->alias][$modelTitleField])) {
|
||||
$modelTitle = $model->data[$model->alias][$modelTitleField];
|
||||
} else if ($this->old[$model->alias][$modelTitleField]) {
|
||||
$modelTitle = $this->old[$model->alias][$modelTitleField];
|
||||
}
|
||||
}
|
||||
|
||||
$modelName = $model->name === 'MispObject' ? 'Object' : $model->name;
|
||||
|
||||
if ($modelName === 'AttributeTag' || $modelName === 'EventTag') {
|
||||
$action = $model->data[$model->alias]['local'] ? AuditLog::ACTION_TAG_LOCAL : AuditLog::ACTION_TAG;
|
||||
$tagInfo = $this->getTagInfo($model, $model->data[$model->alias]['tag_id']);
|
||||
if ($tagInfo) {
|
||||
$modelTitle = $tagInfo['tag_name'];
|
||||
if ($tagInfo['is_galaxy']) {
|
||||
$action = $model->data[$model->alias]['local'] ? AuditLog::ACTION_GALAXY_LOCAL : AuditLog::ACTION_GALAXY;
|
||||
if ($tagInfo['galaxy_cluster_name']) {
|
||||
$modelTitle = $tagInfo['galaxy_cluster_name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$id = $modelName === 'AttributeTag' ? $model->data[$model->alias]['attribute_id'] : $model->data[$model->alias]['event_id'];
|
||||
$modelName = $modelName === 'AttributeTag' ? 'Attribute' : 'Event';
|
||||
}
|
||||
|
||||
if ($modelName === 'Event') {
|
||||
if (isset($changedFields['published'][1]) && $changedFields['published'][1]) {
|
||||
$action = AuditLog::ACTION_PUBLISH;
|
||||
} else if (isset($changedFields['sighting_timestamp'][1]) && $changedFields['sighting_timestamp'][1]) {
|
||||
$action = AuditLog::ACTION_PUBLISH_SIGHTINGS;
|
||||
}
|
||||
}
|
||||
|
||||
$this->auditLog()->insert([
|
||||
'action' => $action,
|
||||
'model' => $modelName,
|
||||
'model_id' => $id,
|
||||
'model_title' => $modelTitle,
|
||||
'event_id' => $eventId,
|
||||
'change' => $changedFields,
|
||||
]);
|
||||
}
|
||||
|
||||
public function beforeDelete(Model $model, $cascade = true)
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return true;
|
||||
}
|
||||
$model->recursive = -1;
|
||||
$model->read();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function afterDelete(Model $model)
|
||||
{
|
||||
if (!$this->enabled) {
|
||||
return;
|
||||
}
|
||||
if ($model->name === 'Event') {
|
||||
$eventId = $model->id;
|
||||
} else {
|
||||
$eventId = isset($model->data[$model->alias]['event_id']) ? $model->data[$model->alias]['event_id'] : null;
|
||||
}
|
||||
|
||||
$modelTitle = null;
|
||||
if (isset($this->modelInfo[$model->name])) {
|
||||
$modelTitleField = $this->modelInfo[$model->name];
|
||||
if (is_callable($modelTitleField)) {
|
||||
$modelTitle = $modelTitleField($model->data[$model->alias], []);
|
||||
} else if (isset($model->data[$model->alias][$modelTitleField])) {
|
||||
$modelTitle = $model->data[$model->alias][$modelTitleField];
|
||||
}
|
||||
}
|
||||
|
||||
$modelName = $model->name === 'MispObject' ? 'Object' : $model->name;
|
||||
$action = AuditLog::ACTION_DELETE;
|
||||
$id = $model->id;
|
||||
|
||||
if ($modelName === 'AttributeTag' || $modelName === 'EventTag') {
|
||||
$action = $model->data[$model->alias]['local'] ? AuditLog::ACTION_REMOVE_TAG_LOCAL : AuditLog::ACTION_REMOVE_TAG;
|
||||
$tagInfo = $this->getTagInfo($model, $model->data[$model->alias]['tag_id']);
|
||||
if ($tagInfo) {
|
||||
$modelTitle = $tagInfo['tag_name'];
|
||||
if ($tagInfo['is_galaxy']) {
|
||||
$action = $model->data[$model->alias]['local'] ? AuditLog::ACTION_REMOVE_GALAXY_LOCAL : AuditLog::ACTION_REMOVE_GALAXY;
|
||||
if ($tagInfo['galaxy_cluster_name']) {
|
||||
$modelTitle = $tagInfo['galaxy_cluster_name'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$id = $modelName === 'AttributeTag' ? $model->data[$model->alias]['attribute_id'] : $model->data[$model->alias]['event_id'];
|
||||
$modelName = $modelName === 'AttributeTag' ? 'Attribute' : 'Event';
|
||||
}
|
||||
|
||||
$this->auditLog()->insert([
|
||||
'action' => $action,
|
||||
'model' => $modelName,
|
||||
'model_id' => $id,
|
||||
'model_title' => $modelTitle,
|
||||
'event_id' => $eventId,
|
||||
'change' => $this->changedFields($model),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
* @param int $tagId
|
||||
* @return array|null
|
||||
*/
|
||||
private function getTagInfo(Model $model, $tagId)
|
||||
{
|
||||
$tag = $model->Tag->find('first', [
|
||||
'conditions' => ['Tag.id' => $tagId],
|
||||
'recursive' => -1,
|
||||
'fields' => ['Tag.name', 'Tag.is_galaxy'],
|
||||
]);
|
||||
if (empty($tag)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$galaxyClusterName = null;
|
||||
if ($tag['Tag']['is_galaxy']) {
|
||||
if (!isset($this->GalaxyCluster)) {
|
||||
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
|
||||
}
|
||||
$galaxyCluster = $this->GalaxyCluster->find('first', [
|
||||
'conditions' => ['GalaxyCluster.tag_name' => $tag['Tag']['name']],
|
||||
'recursive' => -1,
|
||||
'fields' => ['GalaxyCluster.value'],
|
||||
]);
|
||||
if (!empty($galaxyCluster)) {
|
||||
$galaxyClusterName = $galaxyCluster['GalaxyCluster']['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'tag_name' => $tag['Tag']['name'],
|
||||
'is_galaxy' => $tag['Tag']['is_galaxy'],
|
||||
'galaxy_cluster_name' => $galaxyClusterName,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Model $model
|
||||
* @param array|null $fieldsToSave
|
||||
* @return array
|
||||
*/
|
||||
private function changedFields(Model $model, $fieldsToSave = null)
|
||||
{
|
||||
$dbFields = $model->schema();
|
||||
$changedFields = [];
|
||||
foreach ($model->data[$model->alias] as $key => $value) {
|
||||
if (isset($this->skipFields[$key])) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($dbFields[$key])) {
|
||||
continue;
|
||||
}
|
||||
if ($fieldsToSave && !in_array($key, $fieldsToSave, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isset($model->data[$model->alias][$model->primaryKey]) && isset($this->old[$model->alias][$key])) {
|
||||
$old = $this->old[$model->alias][$key];
|
||||
} else {
|
||||
$old = null;
|
||||
}
|
||||
|
||||
// Normalize
|
||||
if (is_bool($old)) {
|
||||
$old = $old ? 1 : 0;
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
$value = $value ? 1 : 0;
|
||||
}
|
||||
$dbType = $dbFields[$key]['type'];
|
||||
if ($dbType === 'integer' || $dbType === 'tinyinteger' || $dbType === 'biginteger' || $dbType === 'boolean') {
|
||||
$value = (int)$value;
|
||||
if ($old !== null) {
|
||||
$old = (int)$old;
|
||||
}
|
||||
}
|
||||
|
||||
if ($value == $old) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($key === 'password' || $key === 'authkey') {
|
||||
$value = '*****';
|
||||
if ($old !== null) {
|
||||
$old = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if ($old === null) {
|
||||
$changedFields[$key] = $value;
|
||||
} else {
|
||||
$changedFields[$key] = [$old, $value];
|
||||
}
|
||||
}
|
||||
|
||||
return $changedFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AuditLog
|
||||
*/
|
||||
private function auditLog()
|
||||
{
|
||||
if ($this->AuditLog === null) {
|
||||
$this->AuditLog = ClassRegistry::init('AuditLog');
|
||||
}
|
||||
return $this->AuditLog;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ App::uses('AppModel', 'Model');
|
|||
class Cerebrate extends AppModel
|
||||
{
|
||||
public $actsAs = [
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => [
|
||||
'roleModel' => 'Role',
|
||||
'roleKey' => 'role_id',
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
App::uses('AppModel', 'Model');
|
||||
App::uses('RandomTool', 'Tools');
|
||||
|
||||
/**
|
||||
* @property Attribute $Attribute
|
||||
*/
|
||||
class Correlation extends AppModel
|
||||
{
|
||||
|
||||
public $cache_name = 'misp:top_correlations';
|
||||
public $cache_age = 'misp:top_correlations_age';
|
||||
const CACHE_NAME = 'misp:top_correlations',
|
||||
CACHE_AGE = 'misp:top_correlations_age';
|
||||
|
||||
public $belongsTo = array(
|
||||
'Attribute' => [
|
||||
|
@ -19,6 +21,8 @@ class Correlation extends AppModel
|
|||
)
|
||||
);
|
||||
|
||||
private $exclusions = [];
|
||||
|
||||
public function correlateValueRouter($value)
|
||||
{
|
||||
if (Configure::read('MISP.background_jobs')) {
|
||||
|
@ -57,7 +61,7 @@ class Correlation extends AppModel
|
|||
$a = $a['Attribute'];
|
||||
}
|
||||
$extraConditions = null;
|
||||
if (in_array($a['type'], array('ip-src', 'ip-dst', 'ip-src|port', 'ip-dst|port'))) {
|
||||
if (in_array($a['type'], ['ip-src', 'ip-dst', 'ip-src|port', 'ip-dst|port'], true)) {
|
||||
$extraConditions = $this->cidrCorrelation($a);
|
||||
} else if ($a['type'] === 'ssdeep' && function_exists('ssdeep_fuzzy_compare')) {
|
||||
$extraConditions = $this->ssdeepCorrelation($a);
|
||||
|
@ -199,21 +203,18 @@ class Correlation extends AppModel
|
|||
}
|
||||
}
|
||||
foreach ($correlatingAttributes as $k => $correlatingAttribute) {
|
||||
foreach ($correlatingAttributes as $k2 => $correlatingAttribute2) {
|
||||
foreach ($correlatingAttributes as $correlatingAttribute2) {
|
||||
$correlations = $this->__addCorrelationEntry($value, $correlatingAttribute, $correlatingAttribute2, $correlations);
|
||||
}
|
||||
$extraCorrelations = $this->__addAdvancedCorrelations($correlatingAttribute);
|
||||
if (!empty($extraCorrelations)) {
|
||||
foreach ($extraCorrelations as $k3 => $extraCorrelation) {
|
||||
foreach ($extraCorrelations as $extraCorrelation) {
|
||||
$correlations = $this->__addCorrelationEntry($value, $correlatingAttribute, $extraCorrelation, $correlations);
|
||||
//$correlations = $this->__addCorrelationEntry($value, $extraCorrelation, $correlatingAttribute, $correlations);
|
||||
}
|
||||
}
|
||||
if ($jobId && $k % 100 === 0) {
|
||||
$job['Job']['progress'] = floor(100 * $k / $count);
|
||||
$job['Job']['date_modified'] = date("Y-m-d H:i:s");
|
||||
$job['Job']['message'] = __('Correlating Attributes based on value. %s attributes correlated out of %s.', $k, $count);
|
||||
$this->Job->save($job);
|
||||
$this->Job->saveProgress($jobId, __('Correlating Attributes based on value. %s attributes correlated out of %s.', $k, $count), floor(100 * $k / $count));
|
||||
}
|
||||
}
|
||||
return $this->__saveCorrelations($correlations);
|
||||
|
@ -289,7 +290,7 @@ class Correlation extends AppModel
|
|||
// generate additional correlating attribute list based on the advanced correlations
|
||||
$extraConditions = $this->__buildAdvancedCorrelationConditions($a);
|
||||
$correlatingValues = array($a['value1']);
|
||||
if (!empty($a['value2']) && !in_array($a['type'], $this->Attribute->primaryOnlyCorrelatingTypes)) {
|
||||
if (!empty($a['value2']) && !in_array($a['type'], $this->Attribute->primaryOnlyCorrelatingTypes, true)) {
|
||||
$correlatingValues[] = $a['value2'];
|
||||
}
|
||||
|
||||
|
@ -356,13 +357,10 @@ class Correlation extends AppModel
|
|||
}
|
||||
if (empty($this->exclusions)) {
|
||||
try {
|
||||
$this->redis = $this->setupRedisWithException();
|
||||
$redis = $this->setupRedisWithException();
|
||||
$this->exclusions = $redis->sMembers('misp:correlation_exclusions');
|
||||
} catch (Exception $e) {
|
||||
$redisFail = true;
|
||||
}
|
||||
if (empty($redisFail)) {
|
||||
$this->Correlation = ClassRegistry::init('Correlation');
|
||||
$this->exclusions = $this->redis->sMembers('misp:correlation_exclusions');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
foreach ($this->exclusions as $exclusion) {
|
||||
|
@ -394,7 +392,7 @@ class Correlation extends AppModel
|
|||
return false;
|
||||
}
|
||||
|
||||
public function ssdeepCorrelation($a)
|
||||
private function ssdeepCorrelation($a)
|
||||
{
|
||||
if (empty($this->FuzzyCorrelateSsdeep)) {
|
||||
$this->FuzzyCorrelateSsdeep = ClassRegistry::init('FuzzyCorrelateSsdeep');
|
||||
|
@ -422,7 +420,7 @@ class Correlation extends AppModel
|
|||
return false;
|
||||
}
|
||||
|
||||
public function cidrCorrelation($a)
|
||||
private function cidrCorrelation($a)
|
||||
{
|
||||
$ipValues = array();
|
||||
$ip = $a['value1'];
|
||||
|
@ -437,7 +435,7 @@ class Correlation extends AppModel
|
|||
'deleted' => 0,
|
||||
);
|
||||
|
||||
if (in_array($this->getDataSource()->config['datasource'], array('Database/Mysql', 'Database/MysqlObserver'))) {
|
||||
if (in_array($this->getDataSource()->config['datasource'], ['Database/Mysql', 'Database/MysqlObserver'])) {
|
||||
// Massive speed up for CIDR correlation. Instead of testing all in PHP, database can do that work much
|
||||
// faster. But these methods are just supported by MySQL.
|
||||
if ($ip_version === 4) {
|
||||
|
@ -446,31 +444,6 @@ class Correlation extends AppModel
|
|||
// Just fetch IP address that fit in CIDR range.
|
||||
$conditions['INET_ATON(value1) BETWEEN ? AND ?'] = array($startIp, $endIp);
|
||||
|
||||
// Just fetch IPv4 address that starts with given prefix. This is fast, because value1 is indexed.
|
||||
// This optimisation is possible just to mask bigger than 8 bites.
|
||||
if ($mask >= 8) {
|
||||
$ipv4Parts = explode('.', $networkIp);
|
||||
$ipv4Parts = array_slice($ipv4Parts, 0, intval($mask / 8));
|
||||
$prefix = implode('.', $ipv4Parts);
|
||||
$conditions['value1 LIKE'] = $prefix . '%';
|
||||
}
|
||||
} else {
|
||||
$conditions[] = 'IS_IPV6(value1)';
|
||||
// Just fetch IPv6 address that starts with given prefix. This is fast, because value1 is indexed.
|
||||
if ($mask >= 16) {
|
||||
$ipv6Parts = explode(':', rtrim($networkIp, ':'));
|
||||
$ipv6Parts = array_slice($ipv6Parts, 0, intval($mask / 16));
|
||||
$prefix = implode(':', $ipv6Parts);
|
||||
$conditions['value1 LIKE'] = $prefix . '%';
|
||||
}
|
||||
}// Massive speed up for CIDR correlation. Instead of testing all in PHP, database can do that work much
|
||||
// faster. But these methods are just supported by MySQL.
|
||||
if ($ip_version === 4) {
|
||||
$startIp = ip2long($networkIp) & ((-1 << (32 - $mask)));
|
||||
$endIp = $startIp + pow(2, (32 - $mask)) - 1;
|
||||
// Just fetch IP address that fit in CIDR range.
|
||||
$conditions['INET_ATON(value1) BETWEEN ? AND ?'] = array($startIp, $endIp);
|
||||
|
||||
// Just fetch IPv4 address that starts with given prefix. This is fast, because value1 is indexed.
|
||||
// This optimisation is possible just to mask bigger than 8 bites.
|
||||
if ($mask >= 8) {
|
||||
|
@ -580,6 +553,10 @@ class Correlation extends AppModel
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function generateTopCorrelationsRouter()
|
||||
{
|
||||
if (Configure::read('MISP.background_jobs')) {
|
||||
|
@ -606,7 +583,7 @@ class Correlation extends AppModel
|
|||
true
|
||||
);
|
||||
$this->Job->saveField('process_id', $process_id);
|
||||
return true;
|
||||
return $jobId;
|
||||
} else {
|
||||
return $this->generateTopCorrelations();
|
||||
}
|
||||
|
@ -615,11 +592,10 @@ class Correlation extends AppModel
|
|||
public function generateTopCorrelations($jobId = false)
|
||||
{
|
||||
try {
|
||||
$this->redis = $this->setupRedisWithException();
|
||||
$redis = $this->setupRedisWithException();
|
||||
} catch (Exception $e) {
|
||||
throw new NotFoundException(__('No redis connection found.'));
|
||||
}
|
||||
$mem_initial = memory_get_usage();
|
||||
$max_id = $this->find('first', [
|
||||
'fields' => ['MAX(id) AS max_id'],
|
||||
'recursive' => -1
|
||||
|
@ -641,54 +617,50 @@ class Correlation extends AppModel
|
|||
}
|
||||
$max_id = $max_id[0]['max_id'];
|
||||
|
||||
$this->redis->del($this->cache_name);
|
||||
$this->redis->set($this->cache_age, time());
|
||||
$redis->del(self::CACHE_NAME);
|
||||
$redis->set(self::CACHE_AGE, time());
|
||||
$chunk_size = 1000000;
|
||||
$max = ceil($max_id / $chunk_size);
|
||||
for ($i = 0; $i < $max; $i++) {
|
||||
$correlations = $this->find('column', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['value'],
|
||||
'conditions' => [
|
||||
'id >' => ($i * $chunk_size),
|
||||
'id >' => $i * $chunk_size,
|
||||
'id <=' => (($i + 1) * $chunk_size)
|
||||
]
|
||||
]);
|
||||
$newElements = count($correlations);
|
||||
$correlations = array_count_values($correlations);
|
||||
$pipeline = $this->redis->pipeline();
|
||||
$pipeline = $redis->pipeline();
|
||||
foreach ($correlations as $correlation => $count) {
|
||||
$pipeline->zadd($this->cache_name, ['INCR'], $count, $correlation);
|
||||
$pipeline->zadd(self::CACHE_NAME, ['INCR'], $count, $correlation);
|
||||
}
|
||||
$pipeline->exec();
|
||||
if ($jobId) {
|
||||
$job['Job']['progress'] = floor(100 * $i / $max);
|
||||
$job['Job']['date_modified'] = date("Y-m-d H:i:s");
|
||||
$job['Job']['message'] = __('Generating top correlations. Processed %s IDs.', ($i * $chunk_size) + $newElements);
|
||||
$this->Job->save($job);
|
||||
$this->Job->saveProgress($jobId, __('Generating top correlations. Processed %s IDs.', ($i * $chunk_size) + $newElements), floor(100 * $i / $max));
|
||||
return $jobId;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function findTop($query)
|
||||
public function findTop(array $query)
|
||||
{
|
||||
try {
|
||||
$this->redis = $this->setupRedisWithException();
|
||||
$redis = $this->setupRedisWithException();
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
$start = $query['limit'] * ($query['page'] -1);
|
||||
$end = $query['limit'] * ($query['page']);
|
||||
$list = $this->redis->zRevRange($this->cache_name, $start, $end, true);
|
||||
$end = $query['limit'] * $query['page'];
|
||||
$list = $redis->zRevRange(self::CACHE_NAME, $start, $end, true);
|
||||
$results = [];
|
||||
foreach ($list as $value => $count) {
|
||||
$results[] = [
|
||||
'Correlation' => [
|
||||
'value' => $value,
|
||||
'count' => $count,
|
||||
'excluded' => $this->redis->sismember('misp:correlation_exclusions', $value)
|
||||
'excluded' => $this->__preventExcludedCorrelations(['value1' => $value]),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
@ -698,10 +670,10 @@ class Correlation extends AppModel
|
|||
public function getTopTime()
|
||||
{
|
||||
try {
|
||||
$this->redis = $this->setupRedisWithException();
|
||||
$redis = $this->setupRedisWithException();
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
return $this->redis->get($this->cache_age);
|
||||
return $redis->get(self::CACHE_AGE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ class CorrelationExclusion extends AppModel
|
|||
public $key = 'misp:correlation_exclusions';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -17,6 +17,7 @@ App::uses('SendEmailTemplate', 'Tools');
|
|||
class Event extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -8,6 +8,7 @@ class EventBlocklist extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -3,7 +3,7 @@ App::uses('AppModel', 'Model');
|
|||
|
||||
class EventDelegation extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $validate = array(
|
||||
'event_id' => array(
|
||||
|
|
|
@ -7,6 +7,7 @@ App::uses('AppModel', 'Model');
|
|||
class EventReport extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
|
@ -271,6 +272,44 @@ class EventReport extends AppModel
|
|||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* buildACLConditions Generate ACL conditions for viewing the report
|
||||
*
|
||||
* @param array $user
|
||||
* @param array $events
|
||||
* @return array
|
||||
*/
|
||||
public function attachReportCountsToEvents(array $user, $events)
|
||||
{
|
||||
$conditions = array();
|
||||
if (!$user['Role']['perm_site_admin']) {
|
||||
$sgids = $this->Event->cacheSgids($user, true);
|
||||
}
|
||||
foreach ($events as $k => $event) {
|
||||
$conditions = [
|
||||
'AND' => [
|
||||
[
|
||||
'Event.id' => $event['Event']['id']
|
||||
]
|
||||
]
|
||||
];
|
||||
if (!$user['Role']['perm_site_admin'] && $event['Event']['org_id'] != $user['org_id']) {
|
||||
$conditions['AND'][] = [
|
||||
'EventReport.distribution' => [1, 2, 3, 5],
|
||||
'AND '=> [
|
||||
'EventReport.distribution' => 4,
|
||||
'EventReport.sharing_group_id' => $sgids,
|
||||
]
|
||||
];
|
||||
}
|
||||
$events[$k]['Event']['report_count'] = $this->find('count', [
|
||||
'conditions' => $conditions
|
||||
]);
|
||||
}
|
||||
return $events;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fetchById Simple ACL-aware method to fetch a report by Id or UUID
|
||||
*
|
||||
|
|
|
@ -6,7 +6,7 @@ App::uses('AppModel', 'Model');
|
|||
*/
|
||||
class EventTag extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $validate = array(
|
||||
'event_id' => array(
|
||||
|
|
|
@ -5,7 +5,9 @@ App::uses('TmpFileTool', 'Tools');
|
|||
|
||||
class Feed extends AppModel
|
||||
{
|
||||
public $actsAs = array('SysLogLogable.SysLogLogable' => array(
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'change' => 'full'
|
||||
),
|
||||
'Trim',
|
||||
|
@ -548,7 +550,16 @@ class Feed extends AppModel
|
|||
return $sources;
|
||||
}
|
||||
|
||||
public function downloadFromFeed($actions, $feed, HttpSocket $HttpSocket = null, $user, $jobId = false)
|
||||
/**
|
||||
* @param array $actions
|
||||
* @param array $feed
|
||||
* @param HttpSocket|null $HttpSocket
|
||||
* @param array $user
|
||||
* @param int|false $jobId
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function downloadFromFeed(array $actions, array $feed, HttpSocket $HttpSocket = null, array $user, $jobId = false)
|
||||
{
|
||||
$total = count($actions['add']) + count($actions['edit']);
|
||||
$currentItem = 0;
|
||||
|
@ -559,10 +570,12 @@ class Feed extends AppModel
|
|||
foreach ($actions['add'] as $uuid) {
|
||||
try {
|
||||
$result = $this->__addEventFromFeed($HttpSocket, $feed, $uuid, $user, $filterRules);
|
||||
if ($result !== 'blocked') {
|
||||
if ($result === true) {
|
||||
$results['add']['success'] = $uuid;
|
||||
} else if ($result !== 'blocked') {
|
||||
$results['add']['fail'] = ['uuid' => $uuid, 'reason' => $result];
|
||||
$this->log("Could not add event '$uuid' from feed {$feed['Feed']['id']}: $result", LOG_WARNING);
|
||||
}
|
||||
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Could not add event '$uuid' from feed {$feed['Feed']['id']}.", $e);
|
||||
$results['add']['fail'] = array('uuid' => $uuid, 'reason' => $e->getMessage());
|
||||
|
@ -577,8 +590,11 @@ class Feed extends AppModel
|
|||
$uuid = $editTarget['uuid'];
|
||||
try {
|
||||
$result = $this->__updateEventFromFeed($HttpSocket, $feed, $uuid, $editTarget['id'], $user, $filterRules);
|
||||
if ($result !== 'blocked') {
|
||||
$results['edit']['success'] = $uuid;
|
||||
if ($result === true) {
|
||||
$results['add']['success'] = $uuid;
|
||||
} else if ($result !== 'blocked') {
|
||||
$results['add']['fail'] = ['uuid' => $uuid, 'reason' => $result];
|
||||
$this->log("Could not edit event '$uuid' from feed {$feed['Feed']['id']}: $result", LOG_WARNING);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Could not edit event '$uuid' from feed {$feed['Feed']['id']}.", $e);
|
||||
|
@ -586,7 +602,7 @@ class Feed extends AppModel
|
|||
}
|
||||
|
||||
$this->__cleanupFile($feed, '/' . $uuid . '.json');
|
||||
if ($currentItem % 10 == 0) {
|
||||
if ($currentItem % 10 === 0) {
|
||||
$this->jobProgress($jobId, null, 100 * (($currentItem + 1) / $total));
|
||||
}
|
||||
$currentItem++;
|
||||
|
@ -869,7 +885,7 @@ class Feed extends AppModel
|
|||
* @param HttpSocket|null $HttpSocket
|
||||
* @param array $feed
|
||||
* @param string $uuid
|
||||
* @param $user
|
||||
* @param array $user
|
||||
* @param array|bool $filterRules
|
||||
* @return array|bool|string
|
||||
* @throws Exception
|
||||
|
@ -879,7 +895,6 @@ class Feed extends AppModel
|
|||
$event = $this->downloadAndParseEventFromFeed($feed, $uuid, $HttpSocket);
|
||||
$event = $this->__prepareEvent($event, $feed, $filterRules);
|
||||
if (is_array($event)) {
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
return $this->Event->_add($event, true, $user);
|
||||
} else {
|
||||
return $event;
|
||||
|
@ -937,13 +952,13 @@ class Feed extends AppModel
|
|||
}
|
||||
|
||||
$HttpSocket = $this->isFeedLocal($this->data) ? null : $this->__setupHttpSocket($this->data);
|
||||
if ($this->data['Feed']['source_format'] == 'misp') {
|
||||
if ($this->data['Feed']['source_format'] === 'misp') {
|
||||
$this->jobProgress($jobId, 'Fetching event manifest.');
|
||||
try {
|
||||
$actions = $this->getNewEventUuids($this->data, $HttpSocket);
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Could not get new event uuids for feed $feedId.", $e);
|
||||
$this->jobProgress($jobId, 'Could not fetch event manifest. See log for more details.');
|
||||
$this->jobProgress($jobId, 'Could not fetch event manifest. See error log for more details.');
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -952,7 +967,7 @@ class Feed extends AppModel
|
|||
}
|
||||
|
||||
$total = count($actions['add']) + count($actions['edit']);
|
||||
$this->jobProgress($jobId, "Fetching $total events.");
|
||||
$this->jobProgress($jobId, __("Fetching %s events.", $total));
|
||||
$result = $this->downloadFromFeed($actions, $this->data, $HttpSocket, $user, $jobId);
|
||||
$this->__cleanupFile($this->data, '/manifest.json');
|
||||
} else {
|
||||
|
|
|
@ -7,6 +7,7 @@ class Galaxy extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -13,6 +13,7 @@ class GalaxyCluster extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -7,6 +7,7 @@ class GalaxyClusterBlocklist extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -8,6 +8,7 @@ class GalaxyClusterRelation extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -4,7 +4,7 @@ App::uses('AppModel', 'Model');
|
|||
class GalaxyClusterRelationTag extends AppModel
|
||||
{
|
||||
public $useTable = 'galaxy_cluster_relation_tags';
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $validate = array(
|
||||
'galaxy_cluster_relation_id' => array(
|
||||
|
|
|
@ -7,6 +7,7 @@ class GalaxyElement extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
);
|
||||
|
||||
|
|
|
@ -155,11 +155,11 @@ class Log extends AppModel
|
|||
$conditions = array();
|
||||
$this->Organisation = ClassRegistry::init('Organisation');
|
||||
if ($org !== 'all') {
|
||||
$org = $this->Organisation->find('first', array('fields' => array('name'), 'recursive' => -1, 'conditions' => array('UPPER(Organisation.name) LIKE' => strtoupper($org))));
|
||||
$org = $this->Organisation->fetchOrg($org);
|
||||
if (empty($org)) {
|
||||
return MethodNotAllowedException('Invalid organisation.');
|
||||
throw new MethodNotAllowedException('Invalid organisation.');
|
||||
}
|
||||
$conditions['org'] = $org['Organisation']['name'];
|
||||
$conditions['org'] = $org['name'];
|
||||
}
|
||||
$conditions['AND']['NOT'] = array('action' => array('login', 'logout', 'changepw'));
|
||||
if ($dataSource == 'Database/Mysql' || $dataSource == 'Database/MysqlObserver') {
|
||||
|
@ -206,6 +206,9 @@ class Log extends AppModel
|
|||
*/
|
||||
public function createLogEntry($user, $action, $model, $modelId = 0, $title = '', $change = '')
|
||||
{
|
||||
if (in_array($action, ['tag', 'galaxy', 'publish', 'publish_sightings'], true) && Configure::read('MISP.log_new_audit')) {
|
||||
return; // Do not store tag changes when new audit is enabled
|
||||
}
|
||||
if ($user === 'SYSTEM') {
|
||||
$user = array('Organisation' => array('name' => 'SYSTEM'), 'email' => 'SYSTEM', 'id' => 0);
|
||||
} else if (!is_array($user)) {
|
||||
|
|
|
@ -15,6 +15,7 @@ class MispObject extends AppModel
|
|||
public $useTable = 'objects';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
|
@ -85,7 +86,33 @@ class MispObject extends AppModel
|
|||
'required' => false,
|
||||
'message' => array('Last seen value should be greater than first seen value')
|
||||
),
|
||||
)
|
||||
),
|
||||
'name' => array(
|
||||
'stringNotEmpty' => array(
|
||||
'rule' => array('stringNotEmpty')
|
||||
),
|
||||
),
|
||||
'meta-category' => array(
|
||||
'stringNotEmpty' => array(
|
||||
'rule' => array('stringNotEmpty')
|
||||
),
|
||||
),
|
||||
'description' => array(
|
||||
'stringNotEmpty' => array(
|
||||
'rule' => array('stringNotEmpty')
|
||||
),
|
||||
),
|
||||
'template_uuid' => array(
|
||||
'uuid' => array(
|
||||
'rule' => 'uuid',
|
||||
'message' => 'Please provide a valid RFC 4122 UUID'
|
||||
),
|
||||
),
|
||||
'template_version' => array(
|
||||
'numeric' => array(
|
||||
'rule' => 'naturalNumber',
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
private $__objectDuplicationCheckCache = [];
|
||||
|
|
|
@ -3,7 +3,7 @@ App::uses('AppModel', 'Model');
|
|||
|
||||
class News extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $validate = array(
|
||||
'message' => array(
|
||||
|
|
|
@ -5,6 +5,7 @@ App::uses('AppModel', 'Model');
|
|||
class ObjectReference extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
|
|
|
@ -5,6 +5,7 @@ App::uses('AppModel', 'Model');
|
|||
class ObjectRelationship extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
|
|
|
@ -5,6 +5,7 @@ App::uses('AppModel', 'Model');
|
|||
class ObjectTemplate extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
|
|
|
@ -7,6 +7,7 @@ class OrgBlocklist extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -12,6 +12,7 @@ class Organisation extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Organisation',
|
||||
|
@ -97,7 +98,7 @@ class Organisation extends AppModel
|
|||
'uuid' => '0',
|
||||
'contacts' => '',
|
||||
'local' => true,
|
||||
'restricted_to_domain' => '',
|
||||
'restricted_to_domain' => '[]',
|
||||
'landingpage' => null
|
||||
);
|
||||
|
||||
|
@ -110,15 +111,19 @@ class Organisation extends AppModel
|
|||
$this->data['Organisation']['uuid'] = strtolower(trim($this->data['Organisation']['uuid']));
|
||||
}
|
||||
$date = date('Y-m-d H:i:s');
|
||||
if (!empty($this->data['Organisation']['restricted_to_domain'])) {
|
||||
$this->data['Organisation']['restricted_to_domain'] = str_replace("\r", '', $this->data['Organisation']['restricted_to_domain']);
|
||||
$this->data['Organisation']['restricted_to_domain'] = explode("\n", $this->data['Organisation']['restricted_to_domain']);
|
||||
foreach ($this->data['Organisation']['restricted_to_domain'] as $k => $v) {
|
||||
$this->data['Organisation']['restricted_to_domain'][$k] = trim($v);
|
||||
if (array_key_exists('restricted_to_domain', $this->data['Organisation'])) {
|
||||
if (!is_array($this->data['Organisation']['restricted_to_domain'])) {
|
||||
$this->data['Organisation']['restricted_to_domain'] = str_replace('\r', '', $this->data['Organisation']['restricted_to_domain']);
|
||||
$this->data['Organisation']['restricted_to_domain'] = explode('\n', $this->data['Organisation']['restricted_to_domain']);
|
||||
}
|
||||
|
||||
$this->data['Organisation']['restricted_to_domain'] = array_values(
|
||||
array_filter(
|
||||
array_map('trim', $this->data['Organisation']['restricted_to_domain'])
|
||||
)
|
||||
);
|
||||
|
||||
$this->data['Organisation']['restricted_to_domain'] = json_encode($this->data['Organisation']['restricted_to_domain']);
|
||||
} else {
|
||||
$this->data['Organisation']['restricted_to_domain'] = '';
|
||||
}
|
||||
if (!isset($this->data['Organisation']['id'])) {
|
||||
$this->data['Organisation']['date_created'] = $date;
|
||||
|
|
|
@ -8,6 +8,7 @@ App::uses('AppModel', 'Model');
|
|||
class Post extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Post',
|
||||
|
|
|
@ -9,6 +9,7 @@ App::uses('AppModel', 'Model');
|
|||
class Regexp extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Role',
|
||||
'roleKey' => 'role_id',
|
||||
|
|
|
@ -39,6 +39,7 @@ class Role extends AppModel
|
|||
);
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Trim',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Role',
|
||||
|
|
|
@ -14,7 +14,9 @@ class Server extends AppModel
|
|||
|
||||
public $name = 'Server';
|
||||
|
||||
public $actsAs = array('SysLogLogable.SysLogLogable' => array(
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
'change' => 'full'
|
||||
|
@ -469,6 +471,7 @@ class Server extends AppModel
|
|||
public function pull($user, $id = null, $technique=false, $server, $jobId = false, $force = false)
|
||||
{
|
||||
if ($jobId) {
|
||||
Configure::write('CurrentUserId', $user['id']);
|
||||
$job = ClassRegistry::init('Job');
|
||||
$job->read(null, $jobId);
|
||||
$email = "Scheduled job";
|
||||
|
@ -2628,24 +2631,32 @@ class Server extends AppModel
|
|||
|
||||
public function dbSpaceUsage()
|
||||
{
|
||||
$inMb = function ($value) {
|
||||
return round($value / 1024 / 1024, 2) . " MB";
|
||||
};
|
||||
|
||||
$result = [];
|
||||
$dataSource = $this->getDataSource()->config['datasource'];
|
||||
if ($dataSource == 'Database/Mysql' || $dataSource == 'Database/MysqlObserver') {
|
||||
if ($dataSource === 'Database/Mysql' || $dataSource === 'Database/MysqlObserver') {
|
||||
$sql = sprintf(
|
||||
'select TABLE_NAME, sum((DATA_LENGTH+INDEX_LENGTH)/1024/1024) AS used, sum(DATA_FREE)/1024/1024 AS reclaimable from information_schema.tables where table_schema = %s group by TABLE_NAME;',
|
||||
'select TABLE_NAME, DATA_LENGTH, INDEX_LENGTH, DATA_FREE from information_schema.tables where table_schema = %s group by TABLE_NAME;',
|
||||
"'" . $this->getDataSource()->config['database'] . "'"
|
||||
);
|
||||
$sqlResult = $this->query($sql);
|
||||
$result = array();
|
||||
|
||||
foreach ($sqlResult as $temp) {
|
||||
foreach ($temp[0] as $k => $v) {
|
||||
$temp[0][$k] = round($v, 2) . 'MB';
|
||||
}
|
||||
$temp[0]['table'] = $temp['tables']['TABLE_NAME'];
|
||||
$result[] = $temp[0];
|
||||
$result[$temp['tables']['TABLE_NAME']] = [
|
||||
'table' => $temp['tables']['TABLE_NAME'],
|
||||
'used' => $inMb($temp['tables']['DATA_LENGTH'] + $temp['tables']['INDEX_LENGTH']),
|
||||
'reclaimable' => $inMb($temp['tables']['DATA_FREE']),
|
||||
'data_in_bytes' => (int) $temp['tables']['DATA_LENGTH'],
|
||||
'index_in_bytes' => (int) $temp['tables']['INDEX_LENGTH'],
|
||||
'reclaimable_in_bytes' => (int) $temp['tables']['DATA_FREE'],
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
|
||||
}
|
||||
else if ($dataSource == 'Database/Postgres') {
|
||||
else if ($dataSource === 'Database/Postgres') {
|
||||
$sql = sprintf(
|
||||
'select TABLE_NAME as table, pg_total_relation_size(%s||%s||TABLE_NAME) as used from information_schema.tables where table_schema = %s group by TABLE_NAME;',
|
||||
"'" . $this->getDataSource()->config['database'] . "'",
|
||||
|
@ -2653,19 +2664,18 @@ class Server extends AppModel
|
|||
"'" . $this->getDataSource()->config['database'] . "'"
|
||||
);
|
||||
$sqlResult = $this->query($sql);
|
||||
$result = array();
|
||||
foreach ($sqlResult as $temp) {
|
||||
foreach ($temp[0] as $k => $v) {
|
||||
if ($k == "table") {
|
||||
continue;
|
||||
}
|
||||
$temp[0][$k] = round($v / 1024 / 1024, 2) . 'MB';
|
||||
$temp[0][$k] = $inMb($v);
|
||||
}
|
||||
$temp[0]['reclaimable'] = '0MB';
|
||||
$temp[0]['reclaimable'] = '0 MB';
|
||||
$result[] = $temp[0];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function redisInfo()
|
||||
|
@ -4460,19 +4470,28 @@ class Server extends AppModel
|
|||
|
||||
public function queryAvailableSyncFilteringRules($server)
|
||||
{
|
||||
$syncFilteringRules = [
|
||||
'error' => '',
|
||||
'data' => []
|
||||
];
|
||||
$HttpSocket = $this->setupHttpSocket($server, null);
|
||||
$uri = $server['Server']['url'] . '/servers/getAvailableSyncFilteringRules';
|
||||
$request = $this->setupSyncRequest($server);
|
||||
$response = $HttpSocket->get($uri, false, $request);
|
||||
if ($response === false) {
|
||||
throw new Exception(__('Connection failed for unknown reason.'));
|
||||
try {
|
||||
$response = $HttpSocket->get($uri, false, $request);
|
||||
if ($response === false) {
|
||||
$syncFilteringRules['error'] = __('Connection failed for unknown reason.');
|
||||
return $syncFilteringRules;
|
||||
}
|
||||
} catch (SocketException $e) {
|
||||
$syncFilteringRules['error'] = __('Connection failed for unknown reason. Error returned: %s', $e->getMessage());
|
||||
return $syncFilteringRules;
|
||||
}
|
||||
|
||||
$syncFilteringRules = [];
|
||||
if ($response->isOk()) {
|
||||
$syncFilteringRules = $this->jsonDecode($response->body());
|
||||
$syncFilteringRules['data'] = $this->jsonDecode($response->body());
|
||||
} else {
|
||||
throw new Exception(__('Reponse was not OK. (HTTP code: %s)', $response->code));
|
||||
$syncFilteringRules['error'] = __('Reponse was not OK. (HTTP code: %s)', $response->code);
|
||||
}
|
||||
return $syncFilteringRules;
|
||||
}
|
||||
|
@ -5217,6 +5236,24 @@ class Server extends AppModel
|
|||
'type' => 'boolean',
|
||||
'null' => true
|
||||
],
|
||||
'log_new_audit' => [
|
||||
'level' => self::SETTING_RECOMMENDED,
|
||||
'description' => __('Enable new audit log system.'),
|
||||
'value' => false,
|
||||
'errorMessage' => '',
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
],
|
||||
'log_new_audit_compress' => [
|
||||
'level' => self::SETTING_OPTIONAL,
|
||||
'description' => __('Compress log changes by brotli algorithm. This will reduce log database size.'),
|
||||
'value' => false,
|
||||
'errorMessage' => '',
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
],
|
||||
'delegation' => array(
|
||||
'level' => 1,
|
||||
'description' => __('This feature allows users to create org only events and ask another organisation to take ownership of the event. This allows organisations to remain anonymous by asking a partner to publish an event for them.'),
|
||||
|
@ -5262,6 +5299,15 @@ class Server extends AppModel
|
|||
'type' => 'boolean',
|
||||
'null' => true
|
||||
),
|
||||
'showEventReportCountOnIndex' => array(
|
||||
'level' => 1,
|
||||
'description' => __('When enabled, the aggregate number of event reports for the event becomes visible to the currently logged in user on the event index UI.'),
|
||||
'value' => false,
|
||||
'errorMessage' => '',
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
),
|
||||
'disableUserSelfManagement' => array(
|
||||
'level' => 1,
|
||||
'description' => __('When enabled only Org and Site admins can edit a user\'s profile.'),
|
||||
|
|
|
@ -20,6 +20,7 @@ class ShadowAttribute extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -9,6 +9,7 @@ App::uses('AppModel', 'Model');
|
|||
class SharingGroup extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'SharingGroup',
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
App::uses('AppModel', 'Model');
|
||||
class SharingGroupOrg extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $belongsTo = array(
|
||||
'SharingGroup' => array(
|
||||
|
|
|
@ -3,7 +3,7 @@ App::uses('AppModel', 'Model');
|
|||
|
||||
class SharingGroupServer extends AppModel
|
||||
{
|
||||
public $actsAs = array('Containable');
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $belongsTo = array(
|
||||
'SharingGroup' => array(
|
||||
|
|
|
@ -15,6 +15,7 @@ class Sightingdb extends AppModel
|
|||
);
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -17,6 +17,7 @@ class SightingdbOrg extends AppModel
|
|||
);
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -12,6 +12,7 @@ class Tag extends AppModel
|
|||
public $displayField = 'name';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Tag',
|
||||
'roleKey' => 'tag_id',
|
||||
|
|
|
@ -9,6 +9,7 @@ class TagCollection extends AppModel
|
|||
public $displayField = 'name';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Trim',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'roleModel' => 'Role',
|
||||
|
|
|
@ -7,6 +7,7 @@ class TagCollectionTag extends AppModel
|
|||
public $useTable = 'tag_collection_tags';
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Trim',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'roleModel' => 'Role',
|
||||
|
|
|
@ -11,6 +11,7 @@ class Taxonomy extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
);
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ App::uses('AppModel', 'Model');
|
|||
class Thread extends AppModel
|
||||
{
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
||||
'roleModel' => 'Thread',
|
||||
|
|
|
@ -216,6 +216,7 @@ class User extends AppModel
|
|||
);
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -7,6 +7,7 @@ class UserSetting extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'SysLogLogable.SysLogLogable' => array(
|
||||
'userModel' => 'User',
|
||||
'userKey' => 'user_id',
|
||||
|
|
|
@ -13,6 +13,7 @@ class Warninglist extends AppModel
|
|||
public $recursive = -1;
|
||||
|
||||
public $actsAs = array(
|
||||
'AuditLog',
|
||||
'Containable',
|
||||
);
|
||||
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
|
||||
App::import('Lib', 'SysLog.SysLog'); // Audit, syslogd, extra
|
||||
|
||||
class SysLogLogableBehavior extends LogableBehavior {
|
||||
class SysLogLogableBehavior extends LogableBehavior
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->defaults['enabled'] = !Configure::read('MISP.log_new_audit');
|
||||
}
|
||||
|
||||
function afterSave(Model $Model, $created, $options = array()) {
|
||||
function afterSave(Model $Model, $created, $options = array()) {
|
||||
if (!$this->settings[$Model->alias]['enabled']) {
|
||||
return true;
|
||||
}
|
||||
|
@ -264,6 +270,10 @@ class SysLogLogableBehavior extends LogableBehavior {
|
|||
$this->settings[$Model->alias] = array_merge($this->defaults, $config);
|
||||
$this->settings[$Model->alias]['ignore'][] = $Model->primaryKey;
|
||||
|
||||
if (!$this->settings[$Model->alias]['enabled']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
if ($this->settings[$Model->alias]['userModel'] != $Model->alias) {
|
||||
$this->UserModel = ClassRegistry::init($this->settings[$Model->alias]['userModel']);
|
||||
|
|
|
@ -1,19 +1,24 @@
|
|||
<div class="allowedlist form">
|
||||
<?php echo $this->Form->create('Allowedlist');?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Add Signature Allowedlist');?></legend>
|
||||
<?php
|
||||
echo $this->Form->input('name', array(
|
||||
'class' => 'input-xxlarge'
|
||||
));
|
||||
|
||||
?>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo $this->Form->button(__('Add'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();
|
||||
$modelForForm = 'Allowedlist';
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'form' => $this->Form,
|
||||
'data' => [
|
||||
'title' => $action == 'add' ? __('Add Signature Allowedlist') : __('Edit Signature Allowedlist'),
|
||||
'model' => $modelForForm,
|
||||
'fields' => [
|
||||
[
|
||||
'field' => 'name',
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action'],
|
||||
],
|
||||
]
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => 'add'));
|
||||
?>
|
||||
if (empty($ajax)) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => $action));
|
||||
}
|
||||
?>
|
|
@ -1,19 +0,0 @@
|
|||
<div class="allowedlist form">
|
||||
<?php echo $this->Form->create('Allowedlist');?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Edit Signature Allowedlist');?></legend>
|
||||
<?php
|
||||
echo $this->Form->input('id');
|
||||
echo $this->Form->input('name', array(
|
||||
'class' => 'input-xxlarge'
|
||||
));
|
||||
?>
|
||||
</fieldset>
|
||||
<?php
|
||||
echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => 'edit', 'id' => $this->Form->value('Allowedlist.id')));
|
||||
?>
|
|
@ -1,48 +0,0 @@
|
|||
<div class="allowedlist index">
|
||||
<h2><?php echo __('Signature Allowedlist');?></h2>
|
||||
<p><?php echo __('Regex entries (in the standard php regex /{regex}/{modifier} format) entered below will restrict matching attributes from being included and data sets retrieved through restSearch.');?></p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?php echo $this->Paginator->sort('id');?></th>
|
||||
<th><?php echo $this->Paginator->sort('name');?></th>
|
||||
<th class="actions"><?php echo __('Actions');?></th>
|
||||
</tr><?php
|
||||
foreach ($list as $item):?>
|
||||
<tr>
|
||||
<td class="short"><?php echo h($item['Allowedlist']['id']);?> </td>
|
||||
<td><?php echo h($item['Allowedlist']['name']);?> </td>
|
||||
<td class="short action-links">
|
||||
<?php echo $this->Html->link('', array('admin' => true, 'action' => 'edit', $item['Allowedlist']['id']), array('class' => 'fa fa-edit', 'title' => __('Edit'), 'aria-label' => __('Edit')));?>
|
||||
<?php echo $this->Form->postLink('', array('admin' => true, 'action' => 'delete', $item['Allowedlist']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete "%s"?', $item['Allowedlist']['name']));?>
|
||||
</td>
|
||||
</tr><?php
|
||||
endforeach;?>
|
||||
</table>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => 'index'));
|
|
@ -1,43 +1,48 @@
|
|||
<div class="allowedlist index">
|
||||
<h2><?php echo __('Signature Allowedlist');?></h2>
|
||||
<p><?php echo __('Regex entries (in the standard php regex /{regex}/{modifier} format) entered below will restrict matching attributes from being included in the IDS flag sensitive exports (such as NIDS exports).');?></p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?php echo $this->Paginator->sort('id');?></th>
|
||||
<th><?php echo $this->Paginator->sort('name');?></th>
|
||||
</tr><?php
|
||||
foreach ($list as $item):?>
|
||||
<tr>
|
||||
<td class="short"><?php echo h($item['Allowedlist']['id']);?> </td>
|
||||
<td><?php echo h($item['Allowedlist']['name']);?> </td>
|
||||
</tr><?php
|
||||
endforeach;?>
|
||||
</table>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
<?php
|
||||
echo $this->element('/genericElements/IndexTable/index_table', array(
|
||||
'data' => array(
|
||||
'data' => $list,
|
||||
'title' =>__('Signature Allowedlist'),
|
||||
'description' => __('Regex entries (in the standard php regex /{regex}/{modifier} format) entered below will restrict matching attributes from being included in the IDS flag sensitive exports (such as NIDS exports).'),
|
||||
'primary_id_path' => 'Allowedlist.id',
|
||||
'fields' => array(
|
||||
array(
|
||||
'name' => __('ID'),
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Allowedlist.id',
|
||||
'element' => 'links',
|
||||
'url' => $baseurl . '/allowedlists/view/%s'
|
||||
),
|
||||
array(
|
||||
'name' => __('Name'),
|
||||
'sort' => 'name',
|
||||
'data_path' => 'Allowedlist.name',
|
||||
),
|
||||
),
|
||||
'actions' => array(
|
||||
array(
|
||||
'url' => $baseurl . '/admin/allowedlists/edit',
|
||||
'url_params_data_paths' => array(
|
||||
'Allowedlist.id'
|
||||
),
|
||||
'icon' => 'edit'
|
||||
),
|
||||
array(
|
||||
'title' => __('Delete'),
|
||||
'url' => $baseurl . '/admin/allowedlists/delete',
|
||||
'url_params_data_paths' => array(
|
||||
'Allowedlist.id'
|
||||
),
|
||||
'postLink' => true,
|
||||
'postLinkConfirm' => __('Are you sure you want to delete the entry?'),
|
||||
'icon' => 'trash',
|
||||
'requirements' => $isSiteAdmin,
|
||||
),
|
||||
)
|
||||
)
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => 'index'));
|
||||
<?= $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'allowedlist', 'menuItem' => 'index')); ?>
|
|
@ -139,8 +139,7 @@ function syncMassEditFormAndSubmit(btn) {
|
|||
submitPopoverForm('<?php echo $id;?>', 'massEdit');
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
$(function() {
|
||||
$('#AttributeDistribution').change(function() {
|
||||
if ($('#AttributeDistribution').val() == 4) $('#SGContainer').show();
|
||||
else $('#SGContainer').hide();
|
||||
|
@ -162,17 +161,18 @@ $(document).ready(function() {
|
|||
});
|
||||
|
||||
$("input, label").on('mouseleave', function(e) {
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
});
|
||||
|
||||
$("input, label").on('mouseover', function(e) {
|
||||
var $e = $(e.target);
|
||||
$('#'+e.currentTarget.id).popover('destroy');
|
||||
$('#'+e.currentTarget.id).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
}).popover('show');
|
||||
if (e.currentTarget.id) {
|
||||
$('#' + e.currentTarget.id).popover('destroy');
|
||||
}
|
||||
}).on('mouseover', function(e) {
|
||||
if (e.currentTarget.id) {
|
||||
$('#' + e.currentTarget.id).popover('destroy');
|
||||
$('#' + e.currentTarget.id).popover({
|
||||
trigger: 'focus',
|
||||
placement: 'right',
|
||||
container: 'body',
|
||||
}).popover('show');
|
||||
}
|
||||
});
|
||||
|
||||
// workaround for browsers like IE and Chrome that do now have an onmouseover on the 'options' of a select.
|
||||
|
|
|
@ -0,0 +1,357 @@
|
|||
<div class="logs index">
|
||||
<h2><?= __('Audit logs') ?></h2>
|
||||
<div>
|
||||
<div id="builder"></div>
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 5px;">
|
||||
<button id="qbSubmit" type="button" class="btn btn-success" style="margin-right: 5px;"> <i class="fa fa-filter"></i> <?= __('Filter'); ?></button>
|
||||
<button id="qbClear" type="button" class="btn btn-xs btn-danger" title="<?= __('Clear filtering rules'); ?>"> <i class="fa fa-times"></i> <?= __('Clear'); ?></button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->Html->script('moment-with-locales');
|
||||
echo $this->Html->script('doT');
|
||||
echo $this->Html->script('extendext');
|
||||
echo $this->Html->css('query-builder.default');
|
||||
echo $this->Html->script('query-builder');
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
var qbOptions = {
|
||||
plugins: {
|
||||
'unique-filter': null,
|
||||
'filter-description' : {
|
||||
mode: 'inline'
|
||||
},
|
||||
},
|
||||
conditions: ['AND'],
|
||||
allow_empty: true,
|
||||
filters: [
|
||||
{
|
||||
id: 'created',
|
||||
label: 'Created',
|
||||
type: 'date',
|
||||
operators: ['greater_or_equal', 'between'],
|
||||
validation: {
|
||||
format: 'YYYY-MM-DD'
|
||||
},
|
||||
plugin: 'datepicker',
|
||||
plugin_config: {
|
||||
format: 'yyyy-mm-dd',
|
||||
todayBtn: 'linked',
|
||||
todayHighlight: true,
|
||||
autoclose: true
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "select",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "action",
|
||||
label: "Action",
|
||||
values: <?= json_encode($actions) ?>
|
||||
},
|
||||
{
|
||||
input: "select",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "model",
|
||||
label: "Model type",
|
||||
values: <?= json_encode($models) ?>
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "integer",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "model_id",
|
||||
label: "Model ID",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "integer",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "event_id",
|
||||
label: "Belongs to event with ID",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "string",
|
||||
operators: [
|
||||
"contains",
|
||||
],
|
||||
unique: true,
|
||||
id: "model_title",
|
||||
label: "Model title",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "ip",
|
||||
label: "IP",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "user",
|
||||
label: "User",
|
||||
description: "User ID or mail",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "integer",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "authkey_id",
|
||||
label: "Authentication key ID",
|
||||
},
|
||||
{
|
||||
input: "select",
|
||||
type: "integer",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "request_type",
|
||||
label: "Request type",
|
||||
values: {0: "Browser", 1: "API", 2: "CLI or background job"}
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "request_id",
|
||||
label: "Request ID",
|
||||
description: "Request ID from X-Request-ID HTTP header",
|
||||
},
|
||||
{
|
||||
input: "text",
|
||||
type: "string",
|
||||
operators: [
|
||||
"equal",
|
||||
],
|
||||
unique: true,
|
||||
id: "org",
|
||||
label: "Organisation",
|
||||
description: "Organisation ID, UUID or name",
|
||||
}
|
||||
],
|
||||
rules: {
|
||||
condition: 'AND',
|
||||
not: false,
|
||||
rules: <?= json_encode($qbRules) ?>,
|
||||
flags: {
|
||||
no_add_group: true,
|
||||
condition_readonly: true,
|
||||
}
|
||||
},
|
||||
icons: {
|
||||
add_group: 'fa fa-plus-square',
|
||||
add_rule: 'fa fa-plus-circle',
|
||||
remove_group: 'fa fa-minus-square',
|
||||
remove_rule: 'fa fa-minus-circle',
|
||||
error: 'fa fa-exclamation-triangle'
|
||||
}
|
||||
};
|
||||
|
||||
$(function() {
|
||||
var $builder = $('#builder');
|
||||
|
||||
// Fix for Bootstrap Datepicker
|
||||
$builder.on('afterUpdateRuleValue.queryBuilder', function (e, rule) {
|
||||
if (rule.filter.plugin === 'datepicker') {
|
||||
rule.$el.find('.rule-value-container input').datepicker('update');
|
||||
}
|
||||
});
|
||||
|
||||
var queryBuilder = $builder.queryBuilder(qbOptions);
|
||||
queryBuilder = queryBuilder[0].queryBuilder;
|
||||
|
||||
$('#qbClear').off('click').on('click', function () {
|
||||
queryBuilder.reset();
|
||||
});
|
||||
|
||||
// Submit on enter
|
||||
$builder.on('keyup', 'input[type=text], select', function (event) {
|
||||
if (event.keyCode === 13) {
|
||||
$('#qbSubmit').click();
|
||||
}
|
||||
});
|
||||
|
||||
$('#qbSubmit').off('click').on('click', function () {
|
||||
var rules = queryBuilder.getRules({skip_empty: true});
|
||||
passedArgs = [];
|
||||
for (var key in rules.rules) {
|
||||
var rule = rules.rules[key];
|
||||
var k = rule.id;
|
||||
var v = rule.value;
|
||||
if (Array.isArray(v)) {
|
||||
v = v.join('||');
|
||||
}
|
||||
passedArgs[k] = v;
|
||||
}
|
||||
|
||||
var url = here;
|
||||
for (var key in passedArgs) {
|
||||
if (typeof key === 'number') {
|
||||
url += "/" + passedArgs[key];
|
||||
} else if (key !== 'page') {
|
||||
url += "/" + key + ":" + encodeURIComponent(passedArgs[key]);
|
||||
}
|
||||
}
|
||||
window.location.href = url;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
$paginator = $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
$paginator .= $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
$paginator .= $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $paginator;
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?= $this->Paginator->sort('created') ?></th>
|
||||
<th><?= $this->Paginator->sort('user_id', __('User')) ?></th>
|
||||
<th><?= $this->Paginator->sort('ip', __('IP')) ?></th>
|
||||
<th><?= $this->Paginator->sort('org_id', __('Org')) ?></th>
|
||||
<th><?= $this->Paginator->sort('action') ?></th>
|
||||
<th><?= __('Model') ?></th>
|
||||
<th><?= __('Title') ?></th>
|
||||
<th><?= __('Change') ?></th>
|
||||
</tr>
|
||||
<?php foreach ($list as $item): ?>
|
||||
<tr>
|
||||
<td class="short"><?= $this->Time->time($item['AuditLog']['created']); ?></td>
|
||||
<td class="short" data-search="user" data-search-value="<?= h($item['AuditLog']['user_id']) ?>"><?php
|
||||
if (isset($item['AuditLog']['user_id']) && $item['AuditLog']['user_id'] == 0) {
|
||||
echo __('SYSTEM');
|
||||
} else if (isset($item['User']['email'])) {
|
||||
echo '<a href="' . $baseurl . '/admin/users/view/' . h($item['User']['id']) . '">' . h($item['User']['email']) . '</a>';
|
||||
} else {
|
||||
echo __('<i>Deleted user #%s</i>', h($item['AuditLog']['user_id']));
|
||||
}
|
||||
|
||||
if ($item['AuditLog']['request_type'] == AuditLog::REQUEST_TYPE_CLI) {
|
||||
echo ' <i class="fas fa-terminal" title="' . __('Action done by CLI or background job') .'"></i>';
|
||||
} else if ($item['AuditLog']['request_type'] == AuditLog::REQUEST_TYPE_API) {
|
||||
$key = $item['AuditLog']['authkey_id'] ? ' ' . __('by auth key #%s', h($item['AuditLog']['authkey_id'])) : '';
|
||||
echo ' <i class="fas fa-cogs" title="' . __('Action done trough API') . $key . '"></i>';
|
||||
}
|
||||
?></td>
|
||||
<td class="short" data-search="ip" data-search-value="<?= h($item['AuditLog']['ip']) ?>"><?= h($item['AuditLog']['ip']) ?></td>
|
||||
<td class="short" data-search="org" data-search-value="<?= h($item['AuditLog']['org_id']) ?>">
|
||||
<?php if (isset($item['Organisation']) && $item['Organisation']['id']) {
|
||||
echo $this->OrgImg->getOrgLogo($item, 24);
|
||||
} else if ($item['AuditLog']['org_id'] != 0) {
|
||||
echo __('<i>Deleted org #%s</i>', h($item['AuditLog']['org_id']));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="short" data-search="action" data-search-value="<?= h($item['AuditLog']['action']) ?>"><?= h($item['AuditLog']['action_human']) ?></td>
|
||||
<td class="short" data-search="model" data-search-value="<?= h($item['AuditLog']['model']) . ':' . h($item['AuditLog']['model_id']) ?>">
|
||||
<?php $title = isset($item['AuditLog']['event_info']) ? ' title="' . __('Event #%s: %s', $item['AuditLog']['event_id'], h($item['AuditLog']['event_info'])) . '"' : '' ?>
|
||||
<?= isset($item['AuditLog']['model_link']) ? '<a href="' . h($item['AuditLog']['model_link']) . '"' . $title . '>' : '' ?>
|
||||
<?= h($item['AuditLog']['model']) . ' #' . h($item['AuditLog']['model_id']) ?>
|
||||
<?= isset($item['AuditLog']['model_link']) ? '</a>' : '' ?>
|
||||
</td>
|
||||
<td class="limitedWidth"><?= h($item['AuditLog']['title']) ?></td>
|
||||
<td ondblclick="showFullChange(<?= h($item['AuditLog']['id']) ?>)"><?= $this->element('AuditLog/change', ['item' => $item]) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<p>
|
||||
<?= $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?= $paginator ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var passedArgs = <?= $passedArgs ?>;
|
||||
|
||||
function showFullChange(id) {
|
||||
$.get(baseurl + "/audit_logs/fullChange/" + id, function(data) {
|
||||
var $popoverFormLarge = $('#popover_form_large');
|
||||
$popoverFormLarge.html(data);
|
||||
$popoverFormLarge.find("span.json").each(function () {
|
||||
$(this).html(syntaxHighlightJson($(this).text()));
|
||||
});
|
||||
openPopup($popoverFormLarge);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
$('td[data-search]').mouseenter(function() {
|
||||
var $td = $(this);
|
||||
if ($td.data('search-value').length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$td.find('#quickEditButton').remove(); // clean all similar if exist
|
||||
var $div = $('<div id="quickEditButton"></div>');
|
||||
$div.addClass('quick-edit-row-div');
|
||||
var $span = $('<span></span>');
|
||||
$span.addClass('fa-as-icon fa fa-search-plus');
|
||||
$span.css('font-size', '12px');
|
||||
$div.append($span);
|
||||
$td.append($div);
|
||||
|
||||
$span.click(function() {
|
||||
if ($td.data('search') === 'model') {
|
||||
var val = $td.data('search-value').split(":");
|
||||
passedArgs['model'] = encodeURIComponent(val[0]);
|
||||
passedArgs['model_id'] = encodeURIComponent(val[1]);
|
||||
} else {
|
||||
passedArgs[$td.data('search')] = encodeURIComponent($td.data('search-value'));
|
||||
}
|
||||
|
||||
var url = here;
|
||||
for (var key in passedArgs) {
|
||||
if (typeof key === 'number') {
|
||||
url += "/" + passedArgs[key];
|
||||
} else if (key !== 'page') {
|
||||
url += "/" + key + ":" + passedArgs[key];
|
||||
}
|
||||
}
|
||||
window.location.href = url;
|
||||
});
|
||||
|
||||
$td.off('mouseleave').on('mouseleave', function() {
|
||||
$div.remove();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?= $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'logs', 'menuItem' => 'listAuditLogs']);
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
<div class="logs index">
|
||||
<h2><?= __('Audit logs for event #%s', $event['Event']['id']) ?></h2>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
$paginator = $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
$paginator .= $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
$paginator .= $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $paginator;
|
||||
?>
|
||||
<li><a href="<?= $baseurl . '/logs/event_index/' . h($event['Event']['id']) ?>"><?= __('Older logs') ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?= $this->Paginator->sort('created') ?></th>
|
||||
<th><?= $this->Paginator->sort('user_id', __('User')) ?></th>
|
||||
<th><?= $this->Paginator->sort('org_id', __('Org')) ?></th>
|
||||
<th><?= $this->Paginator->sort('action') ?></th>
|
||||
<th><?= __('Model') ?></th>
|
||||
<th><?= __('Title') ?></th>
|
||||
<th><?= __('Change') ?></th>
|
||||
</tr>
|
||||
<?php foreach ($list as $item): ?>
|
||||
<tr>
|
||||
<td class="short"><?= $this->Time->time($item['AuditLog']['created']); ?></td>
|
||||
<td class="short"><?php
|
||||
if (isset($item['AuditLog']['user_id']) && $item['AuditLog']['user_id'] == 0) {
|
||||
echo __('SYSTEM');
|
||||
} else if (isset($item['User']['email'])) {
|
||||
echo h($item['User']['email']);
|
||||
} ?></td>
|
||||
<td class="short"><?= isset($item['Organisation']) ? $this->OrgImg->getOrgLogo($item, 24) : '' ?></td>
|
||||
<td class="short"><?= h($item['AuditLog']['action_human']) ?></td>
|
||||
<td class="short"><?= h($item['AuditLog']['model']) . ' #' . h($item['AuditLog']['model_id']) ?></td>
|
||||
<td class="limitedWidth"><?= h($item['AuditLog']['title']) ?></td>
|
||||
<td><?= $this->element('AuditLog/change', ['item' => $item]) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</table>
|
||||
<p>
|
||||
<?= $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?= $paginator ?>
|
||||
<li><a href="<?= $baseurl . '/logs/event_index/' . h($event['Event']['id']) ?>"><?= __('Older logs') ?></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?= $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'event', 'menuItem' => 'eventLog', 'event' => $event, 'mayModify' => $mayModify]);
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<div style="padding: 1em; background: white; word-wrap: break-word;">
|
||||
<?= $this->element('AuditLog/change', ['item' => $log, 'full' => true]) ?>
|
||||
</div>
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
$removeActions = [
|
||||
AuditLog::ACTION_DELETE => true,
|
||||
AuditLog::ACTION_REMOVE_GALAXY_LOCAL => true,
|
||||
AuditLog::ACTION_REMOVE_GALAXY => true,
|
||||
AuditLog::ACTION_REMOVE_TAG => true,
|
||||
AuditLog::ACTION_REMOVE_TAG_LOCAL => true,
|
||||
];
|
||||
|
||||
$full = isset($full) ? $full : false;
|
||||
$formatValue = function($field, $value) use ($full) {
|
||||
if ((strpos($field, 'timestamp') !== false || in_array($field, ['expiration', 'created', 'date_created'], true)) && is_numeric($value)) {
|
||||
$date = date('Y-m-d H:i:s', $value);
|
||||
if ($date !== false) {
|
||||
return '<span title="Original value: ' . h($value) . '">' . h($date) . '</span>';
|
||||
}
|
||||
} else if ($field === 'last_seen' || $field === 'first_seen') {
|
||||
$ls_sec = intval($value / 1000000); // $ls is in micro (10^6)
|
||||
$ls_micro = $value % 1000000;
|
||||
$ls_micro = str_pad($ls_micro, 6, "0", STR_PAD_LEFT);
|
||||
$ls = $ls_sec . '.' . $ls_micro;
|
||||
$date = DateTime::createFromFormat('U.u', $ls)->format('Y-m-d\TH:i:s.u');
|
||||
return '<span title="Original value: ' . h($value) . '">' . h($date) . '</span>';
|
||||
}
|
||||
|
||||
if ($full && is_string($value) && !empty($value) && ($value[0] === '{' || $value[0] === '[') && json_decode($value) !== null) {
|
||||
return '<span class="json">' . h($value) . '</span>';
|
||||
}
|
||||
|
||||
if (!$full && mb_strlen($value) > 64) {
|
||||
$value = mb_substr($value, 0, 64) . '...';
|
||||
}
|
||||
return h(json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
|
||||
};
|
||||
|
||||
if (is_array($item['AuditLog']['change'])) {
|
||||
foreach ($item['AuditLog']['change'] as $field => $values) {
|
||||
echo '<span class="json_key">' . h($field) . ':</span> ';
|
||||
if (isset($removeActions[$item['AuditLog']['action']])) {
|
||||
echo '<span class="json_string">' . $formatValue($field, $values) . '</span> <i class="fas fa-arrow-right json_null"></i> <i class="fas fa-times json_string"></i><br>';
|
||||
} else {
|
||||
if (is_array($values)) {
|
||||
echo '<span class="json_string">' . $formatValue($field, $values[0]) . '</span> ';
|
||||
$value = $values[1];
|
||||
} else {
|
||||
$value = $values;
|
||||
}
|
||||
echo '<i class="fas fa-arrow-right json_null"></i> <span class="json_string">' . $formatValue($field, $value) . '</span><br>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
<?php if (in_array('tags', $columns, true)): ?><th><?= __('Tags') ?></th><?php endif; ?>
|
||||
<?php if (in_array('attribute_count', $columns, true)): ?><th title="<?= __('Attribute Count') ?>"><?= $this->Paginator->sort('attribute_count', __('#Attr.')) ?></th><?php endif; ?>
|
||||
<?php if (in_array('correlations', $columns, true)): ?><th title="<?= __('Correlation Count') ?>"><?= __('#Corr.') ?></th><?php endif; ?>
|
||||
<?php if (in_array('report_count', $columns, true)): ?><th title="<?= __('Report Count') ?>"><?= $this->Paginator->sort('report_count', __('#Reports')) ?></th><?php endif; ?>
|
||||
<?php if (in_array('sightings', $columns, true)): ?><th title="<?= __('Sighting Count')?>"><?= __('#Sightings') ?></th><?php endif; ?>
|
||||
<?php if (in_array('proposals', $columns, true)): ?><th title="<?= __('Proposal Count') ?>"><?= __('#Prop') ?></th><?php endif; ?>
|
||||
<?php if (in_array('discussion', $columns, true)): ?><th title="<?= __('Post Count') ?>"><?= __('#Posts') ?></th><?php endif; ?>
|
||||
|
@ -124,6 +125,11 @@
|
|||
<?php endif; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('report_count', $columns, true)): ?>
|
||||
<td class="bold" style="width:30px;">
|
||||
<?= $event['Event']['report_count']; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<?php if (in_array('sightings', $columns, true)): ?>
|
||||
<td class="bold" style="width:30px;">
|
||||
<?php if (!empty($event['Event']['sightings_count'])): ?>
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?php echo $this->Paginator->sort('id', __('ID'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('org_ci', __('Org'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('role_id', __('Role'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('email');?></th>
|
||||
<?php if (empty(Configure::read('Security.advanced_authkeys'))): ?>
|
||||
<th><?php echo $this->Paginator->sort('authkey');?></th>
|
||||
<?php endif; ?>
|
||||
<th><?php echo $this->Paginator->sort('autoalert', __('Event alert'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('contactalert', __('Contact alert'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('gpgkey', __('PGP Key'));?></th>
|
||||
<?php if (Configure::read('SMIME.enabled')): ?>
|
||||
<th><?php echo $this->Paginator->sort('certif_public', 'S/MIME');?></th>
|
||||
<?php endif; ?>
|
||||
<th><?php echo $this->Paginator->sort('nids_sid', __('NIDS SID'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('termsaccepted', __('Terms accepted'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('current_login', __('Last login'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('date_created', __('Created'));?></th>
|
||||
<?php
|
||||
if (Configure::read('Plugin.CustomAuth_enable') && !Configure::read('Plugin.CustomAuth_required')):
|
||||
?>
|
||||
<th><?php echo $this->Paginator->sort('external_auth_required', Configure::read('Plugin.CustomAuth_name') ? Configure::read('Plugin.CustomAuth_name') : 'External authentication');?></th>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<th><?php echo $this->Paginator->sort('disabled');?></th>
|
||||
<th class="actions"><?php echo __('Actions');?></th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($users as $user): ?>
|
||||
<tr <?php echo $user['User']['disabled'] ? 'class="deleted_row"' : '';?>>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo h($user['User']['id']); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<a href="<?php echo $baseurl; ?>/organisations/view/<?php echo $user['Organisation']['id'];?>"><?php echo h($user['Organisation']['name']); ?> </a>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo $this->Html->link($user['Role']['name'], array('controller' => 'roles', 'action' => 'view', $user['Role']['id'])); ?>
|
||||
</td>
|
||||
<td ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo h($user['User']['email']); ?>
|
||||
</td>
|
||||
<?php if (empty(Configure::read('Security.advanced_authkeys'))): ?>
|
||||
<td class="bold<?= $user['Role']['perm_auth'] ? '' : ' grey'; ?>">
|
||||
<span class="privacy-value quickSelect" data-hidden-value="<?= h($user['User']['authkey']) ?>">****************************************</span> <i class="privacy-toggle fas fa-eye useCursorPointer" title="<?= __('Reveal hidden value') ?>"></i>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo $user['User']['autoalert']? __('Yes') : __('No'); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo $user['User']['contactalert']? __('Yes') : __('No'); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo $user['User']['gpgkey']? 'Yes' : 'No'; ?>
|
||||
</td>
|
||||
<?php if (Configure::read('SMIME.enabled')): ?>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo $user['User']['certif_public']? __('Yes') : __('No'); ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo h($user['User']['nids_sid']); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo ($user['User']['termsaccepted'] == 1) ? __("Yes") : __("No"); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" title="<?php echo !$user['User']['current_login'] ? __('N/A') : h(date("Y-m-d H:i:s",$user['User']['current_login']));?>">
|
||||
<?php echo !$user['User']['current_login'] ? __('N/A') : h(date("Y-m-d", $user['User']['current_login'])); ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" title="<?php echo !$user['User']['current_login'] ? 'N/A' : h(date("Y-m-d H:i:s",$user['User']['current_login']));?>">
|
||||
<?php echo !$user['User']['date_created'] ? __('N/A') : h(date("Y-m-d", $user['User']['date_created'])); ?>
|
||||
</td>
|
||||
<?php
|
||||
if (Configure::read('Plugin.CustomAuth_enable') && !Configure::read('Plugin.CustomAuth_required')):
|
||||
?>
|
||||
<td class="short" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';" title="">
|
||||
<?php echo ($user['User']['external_auth_required'] ? __('Yes') : __('No')); ?>
|
||||
</td>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<td class="short <?php if ($user['User']['disabled']) echo 'red bold';?>" ondblclick="document.location ='<?php echo $this->Html->url(array('admin' => true, 'action' => 'view', $user['User']['id']), true);?>';">
|
||||
<?php echo ($user['User']['disabled'] ? __('Yes') : __('No')); ?>
|
||||
</td>
|
||||
<td class="short action-links">
|
||||
<?php
|
||||
if (($isAclAdmin && (($user['User']['org_id'] == $me['org_id'])) || ('1' == $me['id'])) || ($isSiteAdmin)):
|
||||
?>
|
||||
<span role="button" tabindex="0" class="fa fa-sync useCursorPointer" onClick="initiatePasswordReset('<?php echo $user['User']['id']; ?>');" title="<?php echo __('Create new credentials and inform user');?>" aria-label="<?php echo __('Create new credentials and inform user');?>"></span>
|
||||
<?php
|
||||
echo $this->Html->link('', array('admin' => true, 'action' => 'edit', $user['User']['id']), array('class' => 'fa fa-edit', 'title' => __('Edit'), 'aria-label' => __('Edit')));
|
||||
echo $this->Form->postLink('', array('admin' => true, 'action' => 'delete', $user['User']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete # %s? It is highly recommended to never delete users but to disable them instead.', $user['User']['id']));
|
||||
endif;
|
||||
?>
|
||||
<?php echo $this->Html->link('', array('admin' => true, 'action' => 'view', $user['User']['id']), array('class' => 'fa fa-eye', 'title' => __('View'), 'aria-label' => __('View'))); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;
|
||||
?>
|
||||
</table>
|
|
@ -69,7 +69,16 @@
|
|||
if (!empty($params['type']) && $params['type'] === 'dropdown') {
|
||||
$params['type'] = 'select';
|
||||
}
|
||||
if (!empty($fieldData['description'])) {
|
||||
if (!isset($params['class'])) {
|
||||
$params['class'] = '';
|
||||
}
|
||||
$params['class'] .= ' input-with-description';
|
||||
}
|
||||
$temp = $this->Form->input($fieldData['field'], $params);
|
||||
if (!empty($fieldData['description'])) {
|
||||
$temp .= sprintf('<small class="clear form-field-description apply_css_arrow">%s</small>', h($fieldData['description']));
|
||||
}
|
||||
$fieldsArrayForPersistence []= $modelForForm . Inflector::camelize($fieldData['field']);
|
||||
if (!empty($fieldData['hidden'])) {
|
||||
$temp = '<span class="hidden">' . $temp . '</span>';
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
$data = Hash::extract($row, $field['data_path']);
|
||||
$html = '';
|
||||
if (isset($data['country_code'])) {
|
||||
$html .= $this->Icon->countryFlag($data['country_code']) . ' ';
|
||||
}
|
||||
if ($data['nationality'] !== 'Not specified') {
|
||||
$html .= h($data['nationality']);
|
||||
}
|
||||
echo $html;
|
|
@ -2,7 +2,10 @@
|
|||
$data = Hash::extract($row, $field['data_path']);
|
||||
if (is_array($data)) {
|
||||
if (count($data) > 1) {
|
||||
$data = implode(', ', $data);
|
||||
$implodeGlue = isset($field['array_implode_glue']) ? $field['array_implode_glue'] : ', ';
|
||||
$data = implode($implodeGlue, array_map(function($entry) {
|
||||
return h($entry);
|
||||
}, $data));
|
||||
} else {
|
||||
if (count($data) > 0) {
|
||||
$data = $data[0];
|
||||
|
@ -10,8 +13,7 @@
|
|||
$data = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_bool($data)) {
|
||||
} else if (is_bool($data)) {
|
||||
$data = sprintf(
|
||||
'<i class="black fa fa-%s"></i>',
|
||||
$data ? 'check' : 'times'
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
}
|
||||
echo sprintf(
|
||||
'<input class="select_attribute select" type="checkbox" data-rowid="%s" %s>',
|
||||
'<input class="select_attribute select" ondblclick="event.stopPropagation();" type="checkbox" data-rowid="%s" %s>',
|
||||
h($k),
|
||||
empty($data) ? '' : implode(' ', $data)
|
||||
);
|
||||
|
|
|
@ -94,7 +94,7 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
|
|||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'eventLog',
|
||||
'url' => $baseurl . '/logs/event_index/' . $eventId,
|
||||
'url' => $baseurl . (Configure::read('MISP.log_new_audit') ? '/audit_logs/eventIndex/' : '/logs/event_index/') . $eventId,
|
||||
'text' => __('View Event History')
|
||||
));
|
||||
echo $divider;
|
||||
|
@ -566,7 +566,8 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
|
|||
if ($menuItem == 'edit') {
|
||||
echo $divider;
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => $baseurl . '/admin/allowedlists/edit' . h($id),
|
||||
'url' => $baseurl . '/admin/allowedlists/edit/' . h($id),
|
||||
'element_id' => 'edit',
|
||||
'text' => __('Edit Allowedlist')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
|
||||
|
@ -1030,6 +1031,12 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
|
|||
'url' => $baseurl . '/admin/logs/index',
|
||||
'text' => __('List Logs')
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'listAuditLogs',
|
||||
'url' => $baseurl . '/admin/audit_logs/index',
|
||||
'text' => __('List Audit Logs'),
|
||||
'requirement' => Configure::read('MISP.log_new_audit'),
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'url' => $baseurl . '/admin/logs/search',
|
||||
'text' => __('Search Logs')
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
'disabledSubmitButton' => false, // wether to not draw the submit button
|
||||
'flag_redraw_chosen' => false, // should chosen picker be redraw at drawing time
|
||||
'redraw_debounce_time' => 200,
|
||||
'autofocus' => true,
|
||||
);
|
||||
/**
|
||||
* Supported default option in <Option> fields:
|
||||
|
@ -252,7 +253,7 @@ function submitFunction(clicked, callback) {
|
|||
$flag_addPills = false;
|
||||
?>
|
||||
<?php if ($use_select): ?>
|
||||
<select id="<?php echo $select_id; ?>" autofocus style="height: 100px; margin-bottom: 0px;" <?= $this->GenericPicker->add_select_params($defaults); ?>>
|
||||
<select id="<?php echo $select_id; ?>"<?= $defaults['autofocus'] ? ' autofocus' : '' ?> style="height: 100px; margin-bottom: 0px;" <?= $this->GenericPicker->add_select_params($defaults); ?>>
|
||||
<option></option>
|
||||
<?php
|
||||
foreach ($items as $param) {
|
||||
|
@ -301,7 +302,7 @@ function submitFunction(clicked, callback) {
|
|||
|
||||
<?php elseif (count($items) > 0): ?>
|
||||
<ul class="nav nav-pills">
|
||||
<select id="<?php echo $select_id; ?>" autofocus style="display: none;" <?php echo h($this->GenericPicker->add_select_params($defaults)); ?>></select>
|
||||
<select id="<?php echo $select_id; ?>"<?= $defaults['autofocus'] ? ' autofocus' : '' ?> style="display: none;" <?php echo h($this->GenericPicker->add_select_params($defaults)); ?>></select>
|
||||
<?php
|
||||
foreach ($items as $param) {
|
||||
echo $this->GenericPicker->add_pill($param, $defaults);
|
||||
|
|
|
@ -459,13 +459,18 @@
|
|||
),
|
||||
array(
|
||||
'type' => 'root',
|
||||
'text' => __('Audit'),
|
||||
'text' => __('Logs'),
|
||||
'requirement' => $isAclAudit,
|
||||
'children' => array(
|
||||
array(
|
||||
'text' => __('List Logs'),
|
||||
'url' => $baseurl . '/admin/logs/index'
|
||||
),
|
||||
array(
|
||||
'text' => __('List Audit Logs'),
|
||||
'url' => $baseurl . '/admin/audit_logs/index',
|
||||
'requirement' => Configure::read('MISP.log_new_audit'),
|
||||
),
|
||||
array(
|
||||
'text' => __('Search Logs'),
|
||||
'url' => $baseurl . '/admin/logs/search'
|
||||
|
|
|
@ -118,7 +118,6 @@ $(function() {
|
|||
$('div.notice-pull-rule-fetched.alert-success').show()
|
||||
},
|
||||
function(errorMessage) {
|
||||
showMessage('fail', '<?= __('Could not fetch remote sync filtering rules.') ?>');
|
||||
var regex = /Reponse was not OK\. \(HTTP code: (?<code>\d+)\)/m
|
||||
var matches = errorMessage.match(regex)
|
||||
if (matches !== null) {
|
||||
|
@ -129,6 +128,10 @@ $(function() {
|
|||
$('div.notice-pull-rule-fetched.alert-warning').show().find('.reason').text(errorMessage)
|
||||
$pickerTags.parent().remove()
|
||||
$pickerOrgs.parent().remove()
|
||||
$rootContainer.find('.freetext-button-toggle-tag').collapse('show').remove()
|
||||
$rootContainer.find('.freetext-button-toggle-org').collapse('show').remove()
|
||||
$rootContainer.find('.collapse-freetext-tag').removeClass('collapse')
|
||||
$rootContainer.find('.collapse-freetext-org').removeClass('collapse')
|
||||
},
|
||||
function() {
|
||||
$('div.notice-pull-rule-fetched.alert-primary').hide()
|
||||
|
@ -146,10 +149,11 @@ $(function() {
|
|||
|
||||
function getPullFilteringRules(callback, failCallback, alwaysCallback) {
|
||||
$.getJSON('/servers/queryAvailableSyncFilteringRules/' + serverID, function(availableRules) {
|
||||
callback(availableRules)
|
||||
})
|
||||
.fail(function(jqxhr, textStatus, error) {
|
||||
failCallback(jqxhr.responseJSON.message !== undefined ? jqxhr.responseJSON.message : textStatus)
|
||||
if (availableRules.error.length == 0) {
|
||||
callback(availableRules.data)
|
||||
} else {
|
||||
failCallback(availableRules.error)
|
||||
}
|
||||
})
|
||||
.always(function() {
|
||||
alwaysCallback()
|
||||
|
|
|
@ -12,15 +12,22 @@
|
|||
}
|
||||
function mapIDsToObject($data, $ids) {
|
||||
$result = [];
|
||||
foreach ($ids as $id) {
|
||||
foreach ($data as $i => $entry) {
|
||||
foreach ($ids as $i => $id) {
|
||||
foreach ($data as $j => $entry) {
|
||||
if ($id == $entry['id']) {
|
||||
$result[] = $entry;
|
||||
unset($data[$i]);
|
||||
unset($data[$j]);
|
||||
unset($ids[$i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($ids as $freetextValue) {
|
||||
$result[] = [
|
||||
'name' => $freetextValue,
|
||||
'id' => $freetextValue
|
||||
];
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
$seed = rand();
|
||||
$pickerDisplayed = false;
|
||||
?>
|
||||
<div>
|
||||
<div style="display: flex;" class="rules-widget-container container-seed-<?= $seed ?> scope-<?= Inflector::pluralize(h($scope)) ?>" data-funname="initRuleWidgetPicker<?= $seed ?>">
|
||||
|
@ -29,32 +30,8 @@ $seed = rand();
|
|||
</div>
|
||||
<div style="display: flex; margin: 0 0.5em; flex-shrink: 1; padding-top: 20px;">
|
||||
<div style="display: flex; flex-direction: column;">
|
||||
<?php if(!isset($disableFreeText) || !$disableFreeText): ?>
|
||||
<div class="input-prepend input-append">
|
||||
<button
|
||||
class="btn"
|
||||
type="button"
|
||||
title="<?= __('Move %s to the list of %s to allow', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
aria-label="<?= __('Move %s to the list of %s to allow', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
role="button" tabindex="0"
|
||||
onClick="<?= sprintf("handleFreetextButtonClick('%s', this); ", 'rules-allow') ?>"
|
||||
>
|
||||
<i class="<?= $this->FontAwesome->getClass('caret-left') ?>"></i>
|
||||
</button>
|
||||
<input type="text" style="" placeholder="<?= sprintf('Freetext %s name', h($scopeI18n)) ?>">
|
||||
<button
|
||||
class="btn"
|
||||
type="button"
|
||||
title="<?= __('Move %s to the list of %s to block', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
aria-label="<?= __('Move %s to the list of %s to block', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
role="button" tabindex="0"
|
||||
onClick="<?= sprintf("handleFreetextButtonClick('%s', this); ", 'rules-block') ?>"
|
||||
>
|
||||
<i class="<?= $this->FontAwesome->getClass('caret-right') ?>"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if(!empty($options) || $allowEmptyOptions): ?>
|
||||
<?php $pickerDisplayed = true; ?>
|
||||
<div class="input-prepend input-append">
|
||||
<button
|
||||
class="btn"
|
||||
|
@ -91,6 +68,46 @@ $seed = rand();
|
|||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if(!isset($disableFreeText) || !$disableFreeText): ?>
|
||||
<?php if ($pickerDisplayed): ?>
|
||||
<a
|
||||
data-toggle="collapse" data-target="#collapse-freetext-<?= h($scope) ?>-<?= $seed ?>"
|
||||
class="text-left useCursorPointer freetext-button-toggle-<?= h($scope) ?>"
|
||||
title="<?= __('This text input allows you to add custom values to the rules') ?>"
|
||||
>
|
||||
<i class="fas fa-caret-down fa-rotate"></i>
|
||||
<?= __('Show freetext input') ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<div
|
||||
id="collapse-freetext-<?= h($scope) ?>-<?= $seed ?>"
|
||||
class="collapse collapse-freetext-<?= h($scope) ?>"
|
||||
>
|
||||
<div class="input-prepend input-append" style="margin: 1px;">
|
||||
<button
|
||||
class="btn"
|
||||
type="button"
|
||||
title="<?= __('Move %s to the list of %s to allow', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
aria-label="<?= __('Move %s to the list of %s to allow', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
role="button" tabindex="0"
|
||||
onClick="<?= sprintf("handleFreetextButtonClick('%s', this); ", 'rules-allow') ?>"
|
||||
>
|
||||
<i class="<?= $this->FontAwesome->getClass('caret-left') ?>"></i>
|
||||
</button>
|
||||
<input type="text" style="" placeholder="<?= sprintf('Freetext %s name', h($scopeI18n)) ?>">
|
||||
<button
|
||||
class="btn"
|
||||
type="button"
|
||||
title="<?= __('Move %s to the list of %s to block', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
aria-label="<?= __('Move %s to the list of %s to block', h($scopeI18n), Inflector::pluralize(h($scopeI18n)));?>"
|
||||
role="button" tabindex="0"
|
||||
onClick="<?= sprintf("handleFreetextButtonClick('%s', this); ", 'rules-block') ?>"
|
||||
>
|
||||
<i class="<?= $this->FontAwesome->getClass('caret-right') ?>"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div style="flex-grow: 1;">
|
||||
|
@ -122,15 +139,28 @@ $seed = rand();
|
|||
|
||||
<script>
|
||||
function initRuleWidgetPicker<?= $seed ?>() {
|
||||
$('.container-seed-<?= $seed ?> select.rules-select-picker').chosen()
|
||||
$('.container-seed-<?= $seed ?> select.rules-select-data').keydown(function(evt) {
|
||||
var $baseContainer = $('.container-seed-<?= $seed ?>');
|
||||
$baseContainer.find('select.rules-select-picker').chosen({
|
||||
placeholder_text_multiple: "<?= __('Select some %s', Inflector::humanize(Inflector::pluralize(h($scopeI18n)))); ?>"
|
||||
})
|
||||
$baseContainer.find('select.rules-select-data').keydown(function(evt) {
|
||||
var $select = $(this)
|
||||
var $pickerSelect = $select.closest('.rules-widget-container').find('select.rules-select-picker')
|
||||
if (evt.keyCode === 46) { // <DELETE>
|
||||
deleteSelectedRules($select, $pickerSelect)
|
||||
}
|
||||
});
|
||||
rebuildRules($('.container-seed-<?= $seed ?>'))
|
||||
rebuildRules($baseContainer)
|
||||
$baseContainer.data('initial-rules-allow', $baseContainer.find('.rules-allow').children())
|
||||
$baseContainer.data('initial-rules-block', $baseContainer.find('.rules-block').children())
|
||||
$baseContainer.data('resetrulesfun', function() {
|
||||
$baseContainer.find('.rules-allow').empty().append(
|
||||
$baseContainer.data('initial-rules-allow')
|
||||
)
|
||||
$baseContainer.find('.rules-block').empty().append(
|
||||
$baseContainer.data('initial-rules-block')
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function deleteSelectedRules($select, $pickerSelect) {
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
'sightings' => __('Sightings'),
|
||||
'proposals' => __('Proposals'),
|
||||
'discussion' => __('Posts'),
|
||||
'report_count' => __('Report count')
|
||||
];
|
||||
|
||||
$columnsMenu = [];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="events index">
|
||||
<h2><?php echo __('Event with proposals');?></h2>
|
||||
<h2><?= __('Event with proposals');?></h2>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
|
@ -14,7 +14,7 @@
|
|||
<th class="filter">
|
||||
<?php echo $this->Paginator->sort('published');?>
|
||||
</th>
|
||||
<th><?php echo $this->Paginator->sort('id', 'Id', array('direction' => 'desc'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('id', 'ID', array('direction' => 'desc'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('attribute_count', __('Proposals'));?></th>
|
||||
<th><?php echo __('Contributors');?></th>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
|
@ -30,48 +30,38 @@
|
|||
<?php echo $this->Paginator->sort('distribution');?>
|
||||
</th>
|
||||
</tr>
|
||||
<?php foreach ($events as $event):?>
|
||||
<tr <?php if ($event['Event']['distribution'] == 0) echo 'class = "privateRed"'?>>
|
||||
<td class="short" onclick="document.location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'">
|
||||
<?php
|
||||
if ($event['Event']['published'] == 1) {
|
||||
?>
|
||||
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" class = "icon-ok" title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"></a>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" class = "icon-remove" title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"></a>
|
||||
<?php
|
||||
}?>
|
||||
<?php foreach ($events as $event): ?>
|
||||
<tr<?php if ($event['Event']['distribution'] == 0) echo ' class="privateRed"'?>>
|
||||
<td class="short dblclickElement">
|
||||
<a href="<?= $baseurl."/events/view/".$event['Event']['id'] ?>" title="<?= __('View') ?>" aria-label="<?= __('View') ?>"><i class="<?= $event['Event']['published'] ? 'black fa fa-check' : 'black fa fa-times' ?>"></i></a>
|
||||
</td>
|
||||
<td class="short">
|
||||
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>"><?php echo $event['Event']['id'];?></a>
|
||||
<a href="<?= $baseurl."/events/view/".$event['Event']['id'] ?>" class="dblclickActionElement"><?= $event['Event']['id'] ?></a>
|
||||
</td>
|
||||
<td class="short" onclick="location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'" style="color:red;font-weight:bold;">
|
||||
<?php echo count($event['ShadowAttribute']); ?>
|
||||
<td class="short">
|
||||
<a href="<?= $baseurl."/events/view/".$event['Event']['id'] . '/proposal:1' ?>" style="color:red;font-weight:bold;"><?= $event['Event']['proposal_count']; ?></a>
|
||||
</td>
|
||||
<td class="short">
|
||||
<?php
|
||||
foreach ($event['orgArray'] as $k => $org) {
|
||||
echo $this->OrgImg->getOrgImg(array('name' => $orgs[$org], 'id' => $org, 'size' => 24));
|
||||
if ((1 + $k) < (count($event['orgArray']))) echo '<br />';
|
||||
if ((1 + $k) < (count($event['orgArray']))) echo '<br>';
|
||||
}
|
||||
?>
|
||||
|
||||
</td>
|
||||
<?php if ('true' == $isSiteAdmin): ?>
|
||||
<td class="short" onclick="location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'">
|
||||
<?php echo h($event['User']['email']); ?>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<td class="short dblclickElement">
|
||||
<?php echo h($event['User']['email']); ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="short" onclick="location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'">
|
||||
<?php echo $event['Event']['date']; ?>
|
||||
<td class="short dblclickElement">
|
||||
<?php echo $event['Event']['date']; ?>
|
||||
</td>
|
||||
<td onclick="location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'">
|
||||
<?php echo nl2br(h($event['Event']['info'])); ?>
|
||||
<td class="dblclickElement">
|
||||
<?php echo nl2br(h($event['Event']['info'])); ?>
|
||||
</td>
|
||||
<td class="short <?php if ($event['Event']['distribution'] == 0) echo 'privateRedText';?>" onclick="location.href ='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>'">
|
||||
<?php echo $event['Event']['distribution'] != 3 ? $distributionLevels[$event['Event']['distribution']] : 'All';?>
|
||||
<td class="short dblclickElement <?php if ($event['Event']['distribution'] == 0) echo 'privateRedText';?>">
|
||||
<?= $event['Event']['distribution'] != 3 ? $distributionLevels[$event['Event']['distribution']] : __('All');?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
|
@ -93,5 +83,4 @@
|
|||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event-collection', 'menuItem' => 'viewProposalIndex'));
|
||||
<?= $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event-collection', 'menuItem' => 'viewProposalIndex'));
|
||||
|
|
|
@ -82,8 +82,12 @@
|
|||
$contributorsContent = [];
|
||||
foreach ($contributors as $organisationId => $name) {
|
||||
$org = ['Organisation' => ['id' => $organisationId, 'name' => $name]];
|
||||
$link = $baseurl . "/logs/event_index/" . $event['Event']['id'] . '/' . h($name);
|
||||
$contributorsContent[] = $this->OrgImg->getNameWithImg($org, $link);
|
||||
if (Configure::read('MISP.log_new_audit')) {
|
||||
$link = $baseurl . "/audit_logs/eventIndex/" . h($event['Event']['id']) . '/' . h($organisationId);
|
||||
} else {
|
||||
$link = $baseurl . "/logs/event_index/" . h($event['Event']['id']) . '/' . h($name);
|
||||
}
|
||||
$contributorsContent[] = $this->OrgImg->getNameWithImg($org, $link);
|
||||
}
|
||||
$table_data[] = array(
|
||||
'key' => __('Contributors'),
|
||||
|
|
|
@ -226,6 +226,9 @@
|
|||
'data' => [
|
||||
'title' => __('Set PULL rules'),
|
||||
'content' => [
|
||||
[
|
||||
'html' => sprintf('<h5 style="font-weight: normal;"><i>%s</i></h5>', __('Configure the rules to be applied when PULLing data to the server'))
|
||||
],
|
||||
[
|
||||
'html' => $this->element('serverRuleElements/pull', [
|
||||
'context' => 'feeds',
|
||||
|
@ -259,15 +262,24 @@ var modelContext = 'Feed';
|
|||
$(document).ready(function() {
|
||||
feedDistributionChange();
|
||||
$("#pull_modify").click(function() {
|
||||
$('#genericModal.pull-rule-modal').modal().on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
$('#genericModal.pull-rule-modal').modal()
|
||||
.on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
.on('hidden', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
if ($(this).data('resetrulesfun') !== undefined) {
|
||||
$(this).data('resetrulesfun')()
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
$("#FeedDistribution").change(function() {
|
||||
feedDistributionChange();
|
||||
|
|
|
@ -229,6 +229,9 @@
|
|||
'data' => [
|
||||
'title' => __('Set PULL rules'),
|
||||
'content' => [
|
||||
[
|
||||
'html' => sprintf('<h5 style="font-weight: normal;"><i>%s</i></h5>', __('Configure the rules to be applied when PULLing data from the server'))
|
||||
],
|
||||
[
|
||||
'html' => $this->element('serverRuleElements/pull', [
|
||||
'context' => 'feeds',
|
||||
|
@ -280,18 +283,27 @@ $(document).ready(function() {
|
|||
rules = convertServerFilterRules(rules);
|
||||
feedDistributionChange();
|
||||
$("#pull_modify").click(function() {
|
||||
$('#genericModal.pull-rule-modal').modal().on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
$('#genericModal.pull-rule-modal').modal()
|
||||
.on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
})
|
||||
if (typeof window['cm'] === "object") {
|
||||
window['cm'].refresh()
|
||||
}
|
||||
})
|
||||
if (typeof window['cm'] === "object") {
|
||||
window['cm'].refresh()
|
||||
}
|
||||
});
|
||||
.on('hidden', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
if ($(this).data('resetrulesfun') !== undefined) {
|
||||
$(this).data('resetrulesfun')()
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
$("#FeedDistribution").change(function() {
|
||||
feedDistributionChange();
|
||||
|
|
|
@ -1,53 +1,90 @@
|
|||
<div class="users form">
|
||||
<?php echo $this->Form->create('Organisation', array('enctype' => 'multipart/form-data'));?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('New Organisation'); ?></legend>
|
||||
<p style="font-weight:bold;"><?php echo __('If the organisation should have access to this instance, make sure that the Local organisation setting is checked. <br />If you would only like to add a known external organisation for inclusion in sharing groups, uncheck the Local organisation setting.');?></p>
|
||||
<div style="float:left;width:345px;">
|
||||
<?php echo $this->Form->input('local', array('label' => __('Local organisation'), 'checked' => true));?>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<hr />
|
||||
<p style="font-weight:bold;"><?php echo __('Mandatory fields.');?></p>
|
||||
<div style="float:left;width:345px;">
|
||||
<?php
|
||||
|
||||
echo $this->Form->input('name', array('div' => 'clear', 'style' => 'width:320px;','label' => __('Organisation Identifier'), 'placeholder' => __('Brief organisation identifier')));
|
||||
?>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div style="float:left;width:425px;">
|
||||
<?php
|
||||
echo $this->Form->input('uuid', array('div' => 'clear', 'label' => __('UUID'), 'placeholder' => __('Paste UUID or click generate'), 'style' => 'width:405px;'));
|
||||
?>
|
||||
</div>
|
||||
<span class="btn btn-inverse" role="button" tabindex="0" aria-label="<?php echo __('Generate UUID');?>" title="<?php echo __('Generate a new UUID for the organisation');?>" style="margin-top:25px;" onClick="generateOrgUUID();"><?php echo __('Generate UUID');?></span>
|
||||
<?php
|
||||
echo $this->Form->input('description', array('label' => __('A brief description of the organisation'), 'div' => 'clear', 'class' => 'input-xxlarge', 'type' => 'textarea', 'placeholder' => __('A description of the organisation that is purely informational.')));
|
||||
?>
|
||||
<?php
|
||||
echo $this->Form->input('restricted_to_domain', array('label' => __('Bind user accounts to domains (line separated)'), 'div' => 'clear', 'class' => 'input-xxlarge', 'type' => 'textarea', 'placeholder' => __('Enter a (list of) domain name(s) to enforce when creating users.')));
|
||||
?>
|
||||
<hr />
|
||||
<p style="font-weight:bold;"><?php echo __('The following fields are all optional.');?></p>
|
||||
<?php
|
||||
echo $this->Form->input('logo', array(
|
||||
'error' => array('escape' => false),
|
||||
'type' => 'file',
|
||||
'label' => __('Logo (48×48 PNG or SVG)')
|
||||
));
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
<?php
|
||||
echo $this->Form->input('nationality', array('options' => $countries));
|
||||
echo $this->Form->input('sector', array('placeholder' => __ ('For example "financial".'), 'style' => 'width:300px;'));
|
||||
echo $this->Form->input('type', array('class' => 'input-xxlarge', 'label' => __('Type of organisation'), 'div' => 'clear', 'placeholder' => __('Freetext description of the org.')));
|
||||
echo $this->Form->input('contacts', array('class' => 'input-xxlarge', 'type' => 'textarea', 'div' => 'clear', 'placeholder' => __('You can add some contact details for the organisation here, if applicable.')));
|
||||
?>
|
||||
</fieldset>
|
||||
<?php echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'addOrg'));
|
||||
?>
|
||||
$modelForForm = 'Organisation';
|
||||
echo $this->element('genericElements/Form/genericForm', [
|
||||
'form' => $this->Form,
|
||||
'formOptions' => [
|
||||
'enctype' => 'multipart/form-data',
|
||||
],
|
||||
'data' => [
|
||||
'model' => $modelForForm,
|
||||
'title' => __('%s Organisation', Inflector::Humanize($action)),
|
||||
'fields' => [
|
||||
sprintf('<h4>%s</h4>', __('Mandatory Fields')),
|
||||
[
|
||||
'default' => true,
|
||||
'type' => 'checkbox',
|
||||
'field' => 'local',
|
||||
'label' => __('Local organisation'),
|
||||
'description' => __('If the organisation should have access to this instance, make sure that the Local organisation setting is checked. If you would only like to add a known external organisation for inclusion in sharing groups, uncheck the Local organisation setting.')
|
||||
],
|
||||
[
|
||||
'field' => 'name',
|
||||
'label' => __('Organisation Identifier'),
|
||||
'placeholder' => __('Brief organisation identifier'),
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
[
|
||||
'field' => 'uuid',
|
||||
'label' => __('UUID'),
|
||||
'placeholder' => __('Paste UUID or click generate'),
|
||||
'stayInLine' => true,
|
||||
'class' => 'input-xxlarge'
|
||||
],
|
||||
sprintf('<span class="btn btn-inverse" role="button" tabindex="0" aria-label="%s" title="%s" style="margin-top:25px;margin-left: -132px;border-top-left-radius: 0;border-bottom-left-radius: 0;" onClick="generateOrgUUID();">%s</span>', __('Generate UUID'), __('Generate a new UUID for the organisation'), __('Generate UUID')),
|
||||
sprintf('<h4>%s</h4>', __('Optional Fields')),
|
||||
[
|
||||
'field' => 'description',
|
||||
'type' => 'textarea',
|
||||
'label' => __('A brief description of the organisation'),
|
||||
'placeholder' => __('A description of the organisation that is purely informational.'),
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
[
|
||||
'field' => 'restricted_to_domain',
|
||||
'type' => 'textarea',
|
||||
'label' => __('Bind user accounts to domains (line separated)'),
|
||||
'placeholder' => __('Enter a (list of) domain name(s) to enforce when creating users.'),
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
[
|
||||
'type' => 'file',
|
||||
'field' => 'logo',
|
||||
'error' => array('escape' => false),
|
||||
'label' => __('Logo (48×48 PNG or SVG)'),
|
||||
],
|
||||
[
|
||||
'field' => 'nationality',
|
||||
'options' => $countries,
|
||||
'class' => 'span4',
|
||||
'stayInLine' => 1,
|
||||
],
|
||||
[
|
||||
'field' => 'sector',
|
||||
'placeholder' => __('For example "financial".'),
|
||||
'class' => 'span3',
|
||||
],
|
||||
[
|
||||
'field' => 'type',
|
||||
'label' => __('Type of organisation'),
|
||||
'placeholder' => __('Freetext description of the org.'),
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
[
|
||||
'field' => 'contacts',
|
||||
'type' => 'textarea',
|
||||
'label' => __('Type of organisation'),
|
||||
'placeholder' => __('You can add some contact details for the organisation here, if applicable.'),
|
||||
'class' => 'input-xxlarge',
|
||||
],
|
||||
],
|
||||
'submit' => [
|
||||
'action' => $this->request->params['action']
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', [
|
||||
'menuList' => 'admin',
|
||||
'menuItem' => $action === 'add' ? 'addOrg' : 'editOrg',
|
||||
'orgId' => $action === 'edit' ? $orgId : 0,
|
||||
]);
|
|
@ -1,64 +0,0 @@
|
|||
<div class="users form">
|
||||
<?php echo $this->Form->create('Organisation', array('enctype' => 'multipart/form-data'));?>
|
||||
<fieldset>
|
||||
<legend><?php echo __('Edit Organisation'); ?></legend>
|
||||
<p style="font-weight:bold;"><?php echo __('If the organisation should have access to this instance, make sure that the Local organisation setting is checked. <br />If you would only like to add a known external organisation for inclusion in sharing groups, uncheck the Local organisation setting.');?></p>
|
||||
<div style="float:left;width:345px;">
|
||||
<?php echo $this->Form->input('local', array('label' => __('Local organisation')));?>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<hr />
|
||||
<p style="font-weight:bold;"><?php echo __('Mandatory fields. Leave the UUID field empty if the organisation doesn\'t have a UUID from another instance.');?></p>
|
||||
<div style="float:left;width:345px;">
|
||||
<?php
|
||||
echo $this->Form->input('name', array('div' => 'clear', 'style' => 'width:320px;','label' => __('Organisation Identifier'), 'placeholder' => __('Brief organisation identifier')));
|
||||
?>
|
||||
</div>
|
||||
<div class="clear"></div>
|
||||
<div style="float:left;width:425px;">
|
||||
<?php
|
||||
echo $this->Form->input('uuid', array('div' => 'clear', 'label' => __('UUID'), 'placeholder' => __('Paste UUID or click generate'), 'style' => 'width:405px;'));
|
||||
?>
|
||||
</div>
|
||||
<span role="button" tabindex="0" aria-label="<?php echo __('Generate a new UUID for the organisation');?>" title="<?php echo __('Generate UUID');?>" class="btn btn-inverse" style="margin-top:25px;" onClick="generateOrgUUID();"><?php echo __('Generate UUID');?></span>
|
||||
<?php
|
||||
if (!empty($duplicate_org)):
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
<span class="bold red">
|
||||
<?php echo __('An organisation with the above uuid already exists. Would you like to merge this organisation into the existing one?');?>
|
||||
</span>
|
||||
<a href="#" onClick="getPopup('<?php echo h($id) . '/' . h($duplicate_org); ?>', 'organisations', 'merge', 'admin');"><?php echo __('Click here'); ?></a>
|
||||
<div class="clear"></div>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<?php
|
||||
echo $this->Form->input('description', array('label' => __('A brief description of the organisation'), 'div' => 'clear', 'class' => 'input-xxlarge', 'type' => 'textarea', 'placeholder' => __('A description of the organisation that is purely informational.')));
|
||||
?>
|
||||
<?php
|
||||
echo $this->Form->input('restricted_to_domain', array('label' => __('Bind user accounts to domains (line separated)'), 'div' => 'clear', 'class' => 'input-xxlarge', 'type' => 'textarea', 'placeholder' => __('Enter a (list of) domain name(s) to enforce when creating users.')));
|
||||
?>
|
||||
<hr />
|
||||
<p style="font-weight:bold;"><?php echo __('The following fields are all optional.');?></p>
|
||||
<?php
|
||||
echo $this->Form->input('logo', array(
|
||||
'error' => array('escape' => false),
|
||||
'type' => 'file',
|
||||
'label' => __('Logo (48×48 PNG or SVG)')
|
||||
));
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
<?php
|
||||
echo $this->Form->input('nationality', array('options' => $countries));
|
||||
echo $this->Form->input('sector', array('placeholder' => __('For example "financial".'), 'style' => 'width:300px;'));
|
||||
echo $this->Form->input('type', array('class' => 'input-xxlarge', 'label' => __('Type of organisation'), 'div' => 'clear', 'placeholder' => __('Freetext description of the org.')));
|
||||
echo $this->Form->input('contacts', array('class' => 'input-xxlarge', 'label' => __('Contacts'), 'type' => 'textarea', 'div' => 'clear', 'placeholder' => __('You can add some contact details for the organisation here, if applicable.')));
|
||||
?>
|
||||
</fieldset>
|
||||
<?php echo $this->Form->button(__('Submit'), array('class' => 'btn btn-primary'));
|
||||
echo $this->Form->end();?>
|
||||
</div>
|
||||
<?php
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'editOrg', 'orgId' => $orgId));
|
||||
?>
|
|
@ -1,183 +1,160 @@
|
|||
<div class="organisations index">
|
||||
<?php
|
||||
$texts = array(
|
||||
'all' => array(
|
||||
'text' => __('All organisations'),
|
||||
'extra' => __(', both local and remote')
|
||||
),
|
||||
'external' => array(
|
||||
'text' => __('Known remote organisations'),
|
||||
'extra' => __(' on other instances')
|
||||
),
|
||||
'local' => array(
|
||||
'text' => __('Local organisations'),
|
||||
'extra' => __(' having a presence on this instance')
|
||||
),
|
||||
);
|
||||
if (!in_array($scope, array_keys($texts))) $scope = 'local';
|
||||
$partial = array();
|
||||
foreach($named as $key => $value):
|
||||
if ($key == 'page' || $key == 'viewall'):
|
||||
continue;
|
||||
endif;
|
||||
$partial[] = h($key) . ':' . h($value);
|
||||
endforeach;
|
||||
$viewall_button_text = __('Paginate');
|
||||
if (!$viewall):
|
||||
$viewall_button_text = __('View all');
|
||||
$partial[] = 'viewall:1';
|
||||
endif;
|
||||
?>
|
||||
<h2><?php echo $texts[$scope]['text'] . $texts[$scope]['extra']; ?></h2>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
<li class="all">
|
||||
<a href="<?php echo $baseurl . '/organisations/index/' . implode('/', $partial); ?>"><?php echo $viewall_button_text; ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
$data = array(
|
||||
'children' => array(
|
||||
array(
|
||||
'children' => array(
|
||||
array(
|
||||
'text' => __('Local organisations'),
|
||||
$fullTitle = [
|
||||
'local' => [
|
||||
'main' => __('Local organisations'),
|
||||
'extra' => __(', both local and remote'),
|
||||
],
|
||||
'external' => [
|
||||
'main' => __('Known remote organisations'),
|
||||
'extra' => __(' on other instances'),
|
||||
],
|
||||
'all' => [
|
||||
'main' => __('All organisations'),
|
||||
'extra' => __(' having a presence on this instance'),
|
||||
]
|
||||
];
|
||||
|
||||
echo '<div class="index">';
|
||||
echo $this->element('/genericElements/IndexTable/index_table', [
|
||||
'data' => [
|
||||
'data' => $orgs,
|
||||
'top_bar' => [
|
||||
'children' => [
|
||||
[
|
||||
'children' => [
|
||||
[
|
||||
'text' => $fullTitle['local']['main'],
|
||||
'active' => $scope === 'local',
|
||||
'url' => $baseurl . '/organisations/index/scope:local'
|
||||
),
|
||||
array(
|
||||
'text' => __('Known remote organisations'),
|
||||
],
|
||||
[
|
||||
'text' => $fullTitle['external']['main'],
|
||||
'active' => $scope === 'external',
|
||||
'url' => $baseurl . '/organisations/index/scope:external'
|
||||
),
|
||||
array(
|
||||
'text' => __('All organisations'),
|
||||
],
|
||||
[
|
||||
'text' => $fullTitle['all']['main'],
|
||||
'active' => $scope === 'all',
|
||||
'url' => $baseurl . '/organisations/index/scope:all'
|
||||
),
|
||||
)
|
||||
),
|
||||
array(
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'data' => '',
|
||||
)
|
||||
)
|
||||
);
|
||||
echo $this->element('/genericElements/ListTopBar/scaffold', array('data' => $data));
|
||||
?>
|
||||
<table class="table table-striped table-hover table-condensed">
|
||||
<tr>
|
||||
<th><?php echo $this->Paginator->sort('id');?></th>
|
||||
<th><?php echo __('Logo');?></th>
|
||||
<th><?php echo $this->Paginator->sort('name');?></th>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<th><?php echo $this->Paginator->sort('uuid', 'UUID');?></th>
|
||||
<?php endif; ?>
|
||||
<th><?php echo $this->Paginator->sort('description');?></th>
|
||||
<th><?php echo $this->Paginator->sort('nationality');?></th>
|
||||
<th><?php echo $this->Paginator->sort('sector');?></th>
|
||||
<th><?php echo $this->Paginator->sort('type');?></th>
|
||||
<th><?php echo $this->Paginator->sort('contacts');?></th>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<th><?php echo __('Added by');?></th>
|
||||
<?php endif; ?>
|
||||
<th><?php echo $this->Paginator->sort('local');?></th>
|
||||
<th><?= $this->Paginator->sort('user_count', __('Users'));?></th>
|
||||
<th><?php echo $this->Paginator->sort('restrictions');?></th>
|
||||
<th class="actions"><?php echo __('Actions');?></th>
|
||||
</tr>
|
||||
<?php
|
||||
foreach ($orgs as $org): ?>
|
||||
<tr>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo h($org['Organisation']['id']); ?></td>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'">
|
||||
<?= $this->OrgImg->getOrgLogo($org, 24) ?>
|
||||
</td>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo h($org['Organisation']['name']); ?></td>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'">
|
||||
<span class="quickSelect"><?php echo h($org['Organisation']['uuid']); ?></span>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo h($org['Organisation']['description']); ?></td>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php
|
||||
if (isset($org['Organisation']['country_code'])) {
|
||||
echo $this->Icon->countryFlag($org['Organisation']['country_code']) . ' ';
|
||||
}
|
||||
if ($org['Organisation']['nationality'] !== 'Not specified') {
|
||||
echo h($org['Organisation']['nationality']);
|
||||
}
|
||||
?></td>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo h($org['Organisation']['sector']); ?></td>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo h($org['Organisation']['type']); ?></td>
|
||||
<td><?php echo h($org['Organisation']['contacts']); ?></td>
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<td class="short" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'">
|
||||
<?php echo (isset($org['Organisation']['created_by_email'])) ? h($org['Organisation']['created_by_email']) : ' '; ?>
|
||||
</td>
|
||||
<?php endif; ?>
|
||||
<td class="short <?php echo $org['Organisation']['local'] ? 'green' : 'red';?>" ondblclick="document.location.href ='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id'];?>'"><?php echo $org['Organisation']['local'] ? __('Yes') : __('No');?></td>
|
||||
<td class="short"><?php echo isset($org['Organisation']['user_count']) ? $org['Organisation']['user_count'] : '0';?></td>
|
||||
<td class="short">
|
||||
<?php
|
||||
if (!empty($org['Organisation']['restricted_to_domain'])) {
|
||||
echo implode('<br />', h($org['Organisation']['restricted_to_domain']));
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td class="short action-links">
|
||||
<?php if ($isSiteAdmin): ?>
|
||||
<a href='<?php echo $baseurl . "/admin/organisations/edit/" . $org['Organisation']['id'];?>' class = "fa fa-edit" title = "<?php echo __('Edit');?>" aria-label = "<?php echo __('Edit');?>"></a>
|
||||
<?php
|
||||
echo $this->Form->postLink('', array('admin' => true, 'action' => 'delete', $org['Organisation']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete %s?', $org['Organisation']['name']));
|
||||
?>
|
||||
<?php endif; ?>
|
||||
<a href='<?php echo $baseurl . "/organisations/view/" . $org['Organisation']['id']; ?>' class = "fa fa-eye" title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach; ?>
|
||||
</table>
|
||||
<p>
|
||||
<?php
|
||||
echo $this->Paginator->counter(array(
|
||||
'format' => __('Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}')
|
||||
));
|
||||
?>
|
||||
</p>
|
||||
<div class="pagination">
|
||||
<ul>
|
||||
<?php
|
||||
echo $this->Paginator->prev('« ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
|
||||
echo $this->Paginator->next(__('next') . ' »', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
|
||||
?>
|
||||
<li class="all">
|
||||
<a href="<?php echo $baseurl . '/organisations/index/' . implode('/', $partial); ?>"><?php echo $viewall_button_text; ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
var passedArgsArray = <?php echo $passedArgs; ?>;
|
||||
$(document).ready(function() {
|
||||
$('.searchFilterButton').click(function() {
|
||||
runIndexFilter(this);
|
||||
});
|
||||
$('#quickFilterButton').click(function() {
|
||||
runIndexQuickFilter('/scope:<?php echo h($scope); ?>');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
if ($isSiteAdmin) echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'indexOrg'));
|
||||
else echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'indexOrg'));
|
||||
'cancel' => array(
|
||||
'fa-icon' => 'times',
|
||||
'title' => __('Remove filters'),
|
||||
'onClick' => 'cancelSearch',
|
||||
)
|
||||
]
|
||||
],
|
||||
],
|
||||
'title' => $fullTitle[$scope]['main'] . $fullTitle[$scope]['extra'],
|
||||
'primary_id_path' => 'Organisation.id',
|
||||
'fields' => [
|
||||
[
|
||||
'name' => __('ID'),
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'Organisation.id',
|
||||
'element' => 'links',
|
||||
'url' => $baseurl . '/organisations/view/%s'
|
||||
],
|
||||
[
|
||||
'name' => __('Name'),
|
||||
'sort' => 'name',
|
||||
'data_path' => 'Organisation.name',
|
||||
],
|
||||
[
|
||||
'name' => __('UUID'),
|
||||
'sort' => 'uuid',
|
||||
'data_path' => 'Organisation.uuid',
|
||||
'class' => 'quickSelect',
|
||||
'requirements' => $isSiteAdmin
|
||||
],
|
||||
[
|
||||
'name' => __('Description'),
|
||||
'data_path' => 'Organisation.description',
|
||||
],
|
||||
[
|
||||
'name' => __('Nationality'),
|
||||
'data_path' => 'Organisation',
|
||||
'class' => 'short',
|
||||
'element' => 'country',
|
||||
],
|
||||
[
|
||||
'name' => __('Sector'),
|
||||
'data_path' => 'Organisation.sector',
|
||||
],
|
||||
[
|
||||
'name' => __('Type'),
|
||||
'data_path' => 'Organisation.type',
|
||||
],
|
||||
[
|
||||
'name' => __('Contacts'),
|
||||
'data_path' => 'Organisation.contacts',
|
||||
],
|
||||
[
|
||||
'name' => __('Added by'),
|
||||
'sort' => 'created_by_email',
|
||||
'data_path' => 'Organisation.created_by_email',
|
||||
'requirements' => $isSiteAdmin
|
||||
],
|
||||
[
|
||||
'name' => __('Local'),
|
||||
'sort' => 'local',
|
||||
'element' => 'boolean',
|
||||
'data_path' => 'Organisation.local',
|
||||
'colors' => true,
|
||||
],
|
||||
[
|
||||
'name' => __('Users'),
|
||||
'sort' => 'user_count',
|
||||
'data_path' => 'Organisation.user_count',
|
||||
],
|
||||
[
|
||||
'name' => __('Restrictions'),
|
||||
'sort' => 'restricted_to_domain',
|
||||
'data_path' => 'Organisation.restricted_to_domain',
|
||||
'array_implode_glue' => '<br/>',
|
||||
],
|
||||
],
|
||||
'actions' => [
|
||||
[
|
||||
'url' => '/organisations/view',
|
||||
'url_params_data_paths' => [
|
||||
'Organisation.id'
|
||||
],
|
||||
'icon' => 'eye',
|
||||
'title' => __('View'),
|
||||
'dbclickAction' => true,
|
||||
],
|
||||
[
|
||||
'url' => '/admin/organisations/edit',
|
||||
'url_params_data_paths' => [
|
||||
'Organisation.id'
|
||||
],
|
||||
'icon' => 'edit',
|
||||
'title' => __('Edit'),
|
||||
'requirements' => $isSiteAdmin
|
||||
],
|
||||
[
|
||||
'title' => __('Delete'),
|
||||
'icon' => 'trash',
|
||||
'url' => '/admin/organisations/delete',
|
||||
'url_params_data_paths' => array('Organisation.id'),
|
||||
'postLink' => true,
|
||||
'postLinkConfirm' => __('Are you sure you want to delete the Organisation?'),
|
||||
'requirements' => $isSiteAdmin
|
||||
],
|
||||
]
|
||||
]
|
||||
]);
|
||||
echo '</div>';
|
||||
if ($isSiteAdmin) {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'indexOrg'));
|
||||
} else {
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'indexOrg'));
|
||||
}
|
|
@ -187,6 +187,9 @@
|
|||
'data' => [
|
||||
'title' => __('Set PUSH rules'),
|
||||
'content' => [
|
||||
[
|
||||
'html' => sprintf('<h5 style="font-weight: normal;"><i>%s</i></h5>', __('Configure the rules to be applied when PUSHing data to the server'))
|
||||
],
|
||||
[
|
||||
'html' => $this->element('serverRuleElements/push', [
|
||||
'allTags' => $allTags,
|
||||
|
@ -205,7 +208,8 @@
|
|||
];
|
||||
echo $this->element('genericElements/infoModal', $modalData);
|
||||
$modalData['data']['title'] = __('Set PULL rules');
|
||||
$modalData['data']['content'][0]['html'] = $this->element('serverRuleElements/pull', [
|
||||
$modalData['data']['content'][1]['html'] = sprintf('<h5 style="font-weight: normal;"><i>%s</i></h5>', __('Configure the rules to be applied when PULLing data from the server'));
|
||||
$modalData['data']['content'][1]['html'] = $this->element('serverRuleElements/pull', [
|
||||
'context' => 'servers',
|
||||
'ruleObject' => $pullRules
|
||||
]);
|
||||
|
@ -275,29 +279,47 @@ $(document).ready(function() {
|
|||
});
|
||||
rules = convertServerFilterRules(rules);
|
||||
$("#push_modify").click(function() {
|
||||
$('#genericModal.push-rule-modal').modal().on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
$('#genericModal.push-rule-modal').modal()
|
||||
.on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
.on('hidden', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
if ($(this).data('resetrulesfun') !== undefined) {
|
||||
$(this).data('resetrulesfun')()
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
$("#pull_modify").click(function() {
|
||||
$('#genericModal.pull-rule-modal').modal().on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
$('#genericModal.pull-rule-modal').modal()
|
||||
.on('shown', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
var initFun = $(this).data('funname');
|
||||
if (typeof window[initFun] === 'function') {
|
||||
window[initFun]()
|
||||
}
|
||||
})
|
||||
if (typeof window['cm'] === "object") {
|
||||
window['cm'].refresh()
|
||||
}
|
||||
})
|
||||
if (typeof window['cm'] === "object") {
|
||||
window['cm'].refresh()
|
||||
}
|
||||
});
|
||||
.on('hidden', function () {
|
||||
var $containers = $(this).find('.rules-widget-container')
|
||||
$containers.each(function() {
|
||||
if ($(this).data('resetrulesfun') !== undefined) {
|
||||
$(this).data('resetrulesfun')()
|
||||
}
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
$('#add_cert_file').click(function() {
|
||||
|
|
|
@ -1,181 +1,229 @@
|
|||
<?php
|
||||
echo '<div class="index">';
|
||||
$description = __(
|
||||
'Click %s to reset the API keys of all sync and org admin users in one shot. This will also automatically inform them of their new API keys.',
|
||||
$this->Form->postLink(
|
||||
__('here'),
|
||||
$baseurl . '/users/resetAllSyncAuthKeys',
|
||||
array(
|
||||
'title' => __('Reset all sync user API keys'),
|
||||
'aria-label' => __('Reset all sync user API keys'),
|
||||
'class' => 'bold'
|
||||
),
|
||||
__('Are you sure you wish to reset the API keys of all users with sync privileges?')
|
||||
)
|
||||
);
|
||||
$multiSelectField = array();
|
||||
if (!$this->request->is('ajax')) {
|
||||
// Allow reset Keys, filtering and searching if viewing the /users/index page
|
||||
echo '<div class="index">';
|
||||
$description = __(
|
||||
'Click %s to reset the API keys of all sync and org admin users in one shot. This will also automatically inform them of their new API keys.',
|
||||
$this->Form->postLink(
|
||||
__('here'),
|
||||
$baseurl . '/users/resetAllSyncAuthKeys',
|
||||
array(
|
||||
'title' => __('Reset all sync user API keys'),
|
||||
'aria-label' => __('Reset all sync user API keys'),
|
||||
'class' => 'bold'
|
||||
),
|
||||
__('Are you sure you wish to reset the API keys of all users with sync privileges?')
|
||||
)
|
||||
);
|
||||
$topBar = array(
|
||||
'children' => array(
|
||||
array(
|
||||
'children' => array(
|
||||
array(
|
||||
'class' => 'hidden mass-select',
|
||||
'text' => __('Disable selected users'),
|
||||
'onClick' => "multiSelectToggleField",
|
||||
'onClickParams' => array('admin/users', 'massToggleField', 'disabled', '1')
|
||||
),
|
||||
array(
|
||||
'class' => 'hidden mass-select',
|
||||
'text' => __('Enable selected users'),
|
||||
'onClick' => "multiSelectToggleField",
|
||||
'onClickParams' => array('admin/users', 'massToggleField', 'disabled', '0')
|
||||
),
|
||||
array(
|
||||
'class' => 'hidden mass-select',
|
||||
'text' => __('Disable publish emailing'),
|
||||
'onClick' => "multiSelectToggleField",
|
||||
'onClickParams' => array('admin/users', 'massToggleField', 'autoalert', '0')
|
||||
),
|
||||
array(
|
||||
'class' => 'hidden mass-select',
|
||||
'text' => __('Enable publish emailing'),
|
||||
'onClick' => "multiSelectToggleField",
|
||||
'onClickParams' => array('admin/users', 'massToggleField', 'autoalert', '1')
|
||||
),
|
||||
)
|
||||
),
|
||||
array(
|
||||
'type' => 'simple',
|
||||
'children' => array(
|
||||
array(
|
||||
'id' => 'create-button',
|
||||
'title' => __('Modify filters'),
|
||||
'fa-icon' => 'search',
|
||||
'onClick' => 'getPopup',
|
||||
'onClickParams' => array($urlparams, 'admin/users', 'filterUserIndex')
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'type' => 'simple',
|
||||
'children' => array(
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index',
|
||||
'text' => __('All'),
|
||||
'active' => !isset($passedArgsArray['disabled']),
|
||||
),
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index/searchdisabled:0',
|
||||
'text' => __('Active'),
|
||||
'active' => isset($passedArgsArray['disabled']) && $passedArgsArray['disabled'] === "0",
|
||||
),
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index/searchdisabled:1',
|
||||
'text' => __('Disabled'),
|
||||
'active' => isset($passedArgsArray['disabled']) && $passedArgsArray['disabled'] === "1",
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'searchKey' => 'value',
|
||||
)
|
||||
)
|
||||
);
|
||||
$multiSelectField = array(array(
|
||||
'element' => 'selector',
|
||||
'class' => 'short',
|
||||
'data' => array(
|
||||
'id' => array(
|
||||
'value_path' => 'User.id'
|
||||
)
|
||||
)
|
||||
));
|
||||
} else {
|
||||
$description = '';
|
||||
$topBar = [];
|
||||
}
|
||||
echo $this->element('/genericElements/IndexTable/index_table', array(
|
||||
'data' => array(
|
||||
'data' => $users,
|
||||
'top_bar' => array(
|
||||
'children' => array(
|
||||
'top_bar' => $topBar,
|
||||
'fields' => array_merge(
|
||||
$multiSelectField,
|
||||
array(
|
||||
array(
|
||||
'type' => 'simple',
|
||||
'children' => array(
|
||||
array(
|
||||
'id' => 'create-button',
|
||||
'title' => __('Modify filters'),
|
||||
'fa-icon' => 'search',
|
||||
'onClick' => 'getPopup',
|
||||
'onClickParams' => array($urlparams, 'admin/users', 'filterUserIndex')
|
||||
)
|
||||
)
|
||||
'name' => __('ID'),
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.id'
|
||||
),
|
||||
array(
|
||||
'type' => 'simple',
|
||||
'children' => array(
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index',
|
||||
'text' => __('All'),
|
||||
'active' => !isset($passedArgsArray['disabled']),
|
||||
),
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index/searchdisabled:0',
|
||||
'text' => __('Active'),
|
||||
'active' => isset($passedArgsArray['disabled']) && $passedArgsArray['disabled'] === "0",
|
||||
),
|
||||
array(
|
||||
'url' => $baseurl . '/admin/users/index/searchdisabled:1',
|
||||
'text' => __('Disabled'),
|
||||
'active' => isset($passedArgsArray['disabled']) && $passedArgsArray['disabled'] === "1",
|
||||
)
|
||||
)
|
||||
'name' => __('Org'),
|
||||
'sort' => 'User.org_id',
|
||||
'element' => 'org',
|
||||
'data_path' => 'Organisation'
|
||||
),
|
||||
array(
|
||||
'type' => 'search',
|
||||
'button' => __('Filter'),
|
||||
'placeholder' => __('Enter value to search'),
|
||||
'searchKey' => 'value',
|
||||
'name' => __('Role'),
|
||||
'sort' => 'User.role_id',
|
||||
'class' => 'short',
|
||||
'element' => 'role',
|
||||
'data_path' => 'Role'
|
||||
),
|
||||
array(
|
||||
'name' => __('Email'),
|
||||
'sort' => 'User.email',
|
||||
'data_path' => 'User.email'
|
||||
),
|
||||
array(
|
||||
'name' => __('Authkey'),
|
||||
'sort' => 'User.authkey',
|
||||
'class' => 'bold quickSelect',
|
||||
'data_path' => 'User.authkey',
|
||||
'privacy' => 1,
|
||||
'requirement' => empty(Configure::read('Security.advanced_authkeys'))
|
||||
),
|
||||
array(
|
||||
'name' => __('Event alert'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.autoalert',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.autoalert'
|
||||
),
|
||||
array(
|
||||
'name' => __('Contact alert'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.contactalert',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.contactalert'
|
||||
),
|
||||
array(
|
||||
'name' => __('PGP Key'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.gpgkey',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.gpgkey'
|
||||
),
|
||||
array(
|
||||
'name' => __('S/MIME'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.certif_public',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.certif_public',
|
||||
'requirement' => Configure::read('SMIME.enabled')
|
||||
),
|
||||
array(
|
||||
'name' => __('NIDS SID'),
|
||||
'sort' => 'User.nids_sid',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.nids_sid'
|
||||
),
|
||||
array(
|
||||
'name' => __('Terms Accepted'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.termsaccepted',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.termsaccepted'
|
||||
),
|
||||
array(
|
||||
'name' => __('Last Login'),
|
||||
'sort' => 'User.current_login',
|
||||
'element' => 'datetime',
|
||||
'empty' => __('Never'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.current_login'
|
||||
),
|
||||
array(
|
||||
'name' => __('Created'),
|
||||
'sort' => 'User.date_created',
|
||||
'element' => 'datetime',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.date_created'
|
||||
),
|
||||
array(
|
||||
'name' => (Configure::read('Plugin.CustomAuth_name') ? Configure::read('Plugin.CustomAuth_name') : __('External Auth')),
|
||||
'sort' => 'User.external_auth_required',
|
||||
'element' => 'boolean',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.external_auth_required',
|
||||
'requirement' => (Configure::read('Plugin.CustomAuth_enable') && empty(Configure::read('Plugin.CustomAuth_required')))
|
||||
),
|
||||
array(
|
||||
'name' => __('Monitored'),
|
||||
'element' => 'toggle',
|
||||
'url' => $baseurl . '/admin/users/monitor',
|
||||
'url_params_data_paths' => array(
|
||||
'User.id'
|
||||
),
|
||||
'sort' => 'User.disabled',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.monitored',
|
||||
'requirement' => $isSiteAdmin && Configure::read('Security.user_monitoring_enabled')
|
||||
),
|
||||
array(
|
||||
'name' => __('Disabled'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.disabled',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.disabled'
|
||||
)
|
||||
)
|
||||
),
|
||||
'fields' => array(
|
||||
array(
|
||||
'name' => __('ID'),
|
||||
'sort' => 'id',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.id'
|
||||
),
|
||||
array(
|
||||
'name' => __('Org'),
|
||||
'sort' => 'User.org_id',
|
||||
'element' => 'org',
|
||||
'data_path' => 'Organisation'
|
||||
),
|
||||
array(
|
||||
'name' => __('Role'),
|
||||
'sort' => 'User.role_id',
|
||||
'class' => 'short',
|
||||
'element' => 'role',
|
||||
'data_path' => 'Role'
|
||||
),
|
||||
array(
|
||||
'name' => __('Email'),
|
||||
'sort' => 'User.email',
|
||||
'data_path' => 'User.email'
|
||||
),
|
||||
array(
|
||||
'name' => __('Authkey'),
|
||||
'sort' => 'User.authkey',
|
||||
'class' => 'bold quickSelect',
|
||||
'data_path' => 'User.authkey',
|
||||
'privacy' => 1,
|
||||
'requirement' => empty(Configure::read('Security.advanced_authkeys'))
|
||||
),
|
||||
array(
|
||||
'name' => __('Event alert'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.autoalert',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.autoalert'
|
||||
),
|
||||
array(
|
||||
'name' => __('Contact alert'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.contactalert',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.contactalert'
|
||||
),
|
||||
array(
|
||||
'name' => __('PGP Key'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.gpgkey',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.gpgkey'
|
||||
),
|
||||
array(
|
||||
'name' => __('S/MIME'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.certif_public',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.certif_public',
|
||||
'requirement' => Configure::read('SMIME.enabled')
|
||||
),
|
||||
array(
|
||||
'name' => __('NIDS SID'),
|
||||
'sort' => 'User.nids_sid',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.nids_sid'
|
||||
),
|
||||
array(
|
||||
'name' => __('Terms Accepted'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.termsaccepted',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.termsaccepted'
|
||||
),
|
||||
array(
|
||||
'name' => __('Last Login'),
|
||||
'sort' => 'User.current_login',
|
||||
'element' => 'datetime',
|
||||
'empty' => __('Never'),
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.current_login'
|
||||
),
|
||||
array(
|
||||
'name' => __('Created'),
|
||||
'sort' => 'User.date_created',
|
||||
'element' => 'datetime',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.date_created'
|
||||
),
|
||||
array(
|
||||
'name' => (Configure::read('Plugin.CustomAuth_name') ? Configure::read('Plugin.CustomAuth_name') : __('External Auth')),
|
||||
'sort' => 'User.external_auth_required',
|
||||
'element' => 'boolean',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.external_auth_required',
|
||||
'requirement' => (Configure::read('Plugin.CustomAuth_enable') && empty(Configure::read('Plugin.CustomAuth_required')))
|
||||
),
|
||||
array(
|
||||
'name' => __('Monitored'),
|
||||
'element' => 'toggle',
|
||||
'url' => $baseurl . '/admin/users/monitor',
|
||||
'url_params_data_paths' => array(
|
||||
'User.id'
|
||||
),
|
||||
'sort' => 'User.disabled',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.monitored',
|
||||
'requirement' => $isSiteAdmin && Configure::read('Security.user_monitoring_enabled')
|
||||
),
|
||||
array(
|
||||
'name' => __('Disabled'),
|
||||
'element' => 'boolean',
|
||||
'sort' => 'User.disabled',
|
||||
'class' => 'short',
|
||||
'data_path' => 'User.disabled'
|
||||
)
|
||||
),
|
||||
'title' => __('Users index'),
|
||||
'html' => $description,
|
||||
'actions' => array(
|
||||
|
@ -232,5 +280,7 @@
|
|||
)
|
||||
)
|
||||
));
|
||||
echo '</div>';
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'indexUser'));
|
||||
if (!$this->request->is('ajax')) {
|
||||
echo '</div>';
|
||||
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'indexUser'));
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue