Merge branch 'develop' of github.com:MISP/MISP into develop

pull/7400/head
iglocska 2021-05-07 14:09:54 +02:00
commit fcc1996a2e
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
10 changed files with 203 additions and 60 deletions

View File

@ -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(

View File

@ -1159,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'));
}
@ -1308,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(
@ -1346,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;
@ -1490,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);
@ -1504,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'];
}
@ -1517,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,
@ -1528,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]);
}
}
@ -1542,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));
@ -1562,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);
@ -1663,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'));
}
@ -1711,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);
}
/**

View File

@ -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;

View File

@ -249,9 +249,16 @@ class Attribute extends AppModel
'message' => array('Invalid ISO 8601 format')
),
'last_seen' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
'datetimeOrNull' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
),
'validateLastSeenValue' => array(
'rule' => array('validateLastSeenValue'),
'required' => false,
'message' => array('Last seen value should be greater than first seen value')
),
)
);
@ -716,6 +723,22 @@ class Attribute extends AppModel
return $returnValue || is_null($seen);
}
public function validateLastSeenValue($fields)
{
$ls = $fields['last_seen'];
if (is_null($this->data['Attribute']['first_seen']) || is_null($ls)) {
return true;
}
$converted = $this->ISODatetimeToUTC(['Attribute' => [
'first_seen' => $this->data['Attribute']['first_seen'],
'last_seen' => $ls
]], 'Attribute');
if ($converted['Attribute']['first_seen'] >= $converted['Attribute']['last_seen']) {
return false;
}
return true;
}
private $__hexHashLengths = array(
'authentihash' => 64,
'md5' => 32,

View File

@ -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();

View File

@ -550,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;
@ -561,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());
@ -579,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);
@ -588,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++;
@ -871,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
@ -881,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;
@ -939,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;
}
@ -954,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 {

View File

@ -76,10 +76,43 @@ class MispObject extends AppModel
'message' => array('Invalid ISO 8601 format')
),
'last_seen' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
)
'datetimeOrNull' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
),
'validateLastSeenValue' => array(
'rule' => array('validateLastSeenValue'),
'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 = [];
@ -184,6 +217,22 @@ class MispObject extends AppModel
return $returnValue || is_null($seen);
}
public function validateLastSeenValue($fields)
{
$ls = $fields['last_seen'];
if (is_null($this->data['Object']['first_seen']) || is_null($ls)) {
return true;
}
$converted = $this->Attribute->ISODatetimeToUTC(['Object' => [
'first_seen' => $this->data['Object']['first_seen'],
'last_seen' => $ls
]], 'Object');
if ($converted['Object']['first_seen'] >= $converted['Object']['last_seen']) {
return false;
}
return true;
}
public function afterFind($results, $primary = false)
{
foreach ($results as $k => $v) {

View File

@ -143,9 +143,16 @@ class ShadowAttribute extends AppModel
'message' => array('Invalid ISO 8601 format')
),
'last_seen' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
'datetimeOrNull' => array(
'rule' => array('datetimeOrNull'),
'required' => false,
'message' => array('Invalid ISO 8601 format')
),
'validateLastSeenValue' => array(
'rule' => array('validateLastSeenValue'),
'required' => false,
'message' => array('Last seen value should be greater than first seen value')
),
)
);
@ -452,6 +459,22 @@ class ShadowAttribute extends AppModel
return $this->Attribute->datetimeOrNull($fields);
}
public function validateLastSeenValue($fields)
{
$ls = $fields['last_seen'];
if (is_null($this->data['ShadowAttribute']['first_seen']) || is_null($ls)) {
return true;
}
$converted = $this->Attribute->ISODatetimeToUTC(['ShadowAttribute' => [
'first_seen' => $this->data['ShadowAttribute']['first_seen'],
'last_seen' => $ls
]], 'ShadowAttribute');
if ($converted['ShadowAttribute']['first_seen'] >= $converted['ShadowAttribute']['last_seen']) {
return false;
}
return true;
}
public function setDeleted($id)
{
$this->Behaviors->detach('SysLogLogable.SysLogLogable');

View File

@ -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.

View File

@ -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);