chg: [timeline] Synchronize *-seen at Object and ObjectAttribute level,

few fixes and Improved UI
pull/4743/head
mokaddem 2019-10-28 15:45:33 +01:00
parent 6652b922e6
commit 6eda00f701
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
3 changed files with 108 additions and 94 deletions

View File

@ -630,7 +630,11 @@ class ObjectsController extends AppController
if ((!$this->request->is('post') && !$this->request->is('put'))) {
throw new MethodNotAllowedException(__('This function can only be accessed via POST or PUT'));
}
$object = $this->MispObject->find('first', array('contain' => 'Event', 'recursive' => -1));
$object = $this->MispObject->find('first', array(
'conditions' => array('Object.id' => $id),
'contain' => 'Event',
'recursive' => -1
));
if (empty($object)) {
return $this->RestResponse->saveFailResponse('Objects', 'edit', false, 'Invalid object');
}
@ -664,12 +668,15 @@ class ObjectsController extends AppController
$object['Object'][$changedKey] = $changedField;
$changed = true;
}
$forcedSeenOnElements = array();
if (!$changed) {
return $this->RestResponse->saveSuccessResponse('Objects', 'edit', $id, false, 'nochange');
} elseif ($seen_changed) {
$forcedSeenOnElements[$changedKey] = $changedField;
}
$date = new DateTime();
$object['Object']['timestamp'] = $date->getTimestamp();
$this->MispObject->setObjectSeenMetaFromAttribute($object, false);
$object = $this->MispObject->syncObjectAndAttributeSeen($object, $forcedSeenOnElements);
if ($this->MispObject->save($object)) {
$event = $this->MispObject->Event->find('first', array(
'recursive' => -1,
@ -680,20 +687,7 @@ class ObjectsController extends AppController
$event['Event']['timestamp'] = $date->getTimestamp();
$event['Event']['published'] = 0;
if ($seen_changed) {
// Set seen of object at attribute level
$attributes = $this->MispObject->find('first', array(
'conditions' => array('id' => $object['Object']['id']),
'contain' => array('Attribute')
))['Attribute'];
foreach ($attributes as $k => $attribute) {
if (is_null($attribute['first_seen']) && !is_null($object['Object']['first_seen'])) {
$attributes[$k]['first_seen'] = $object['Object']['first_seen'];
}
if (is_null($attribute['last_seen']) && !is_null($object['Object']['last_seen'])) {
$attributes[$k]['last_seen'] = $object['Object']['last_seen'];
}
}
$this->MispObject->Attribute->saveAttributes($attributes);
$this->MispObject->Attribute->saveAttributes($object['Attribute']);
}
$this->MispObject->Event->save($event, array('fieldList' => array('published', 'timestamp', 'info')));
return $this->RestResponse->saveSuccessResponse('Objects', 'edit', $id, false, 'Field updated');

View File

@ -583,39 +583,43 @@ class MispObject extends AppModel
return $attributes;
}
// EUH????? No sure we should do that. Maybe the other way around??? #FIXME
// delete first/last-seen object attribute and set object's meta accordingly
// set object's meta (fs/ls) and potentially delete objectAttributes
public function setObjectSeenMetaFromAttribute(&$object, $delete=false) {
if ( !$delete && isset($object['Object']['first-seen']) && isset($object['Object']['last-seen'])) {
return;
// Set Object's *-seen (and ObjectAttribute's *-seen and ObjectAttribute's value if requested) to the provided *-seen value
// Therefore, synchronizing the 3 values
public function syncObjectAndAttributeSeen($object, $forcedSeenOnElements, $applyOnAttribute=True) {
if (empty($forcedSeenOnElements)) {
return $object;
}
if (isset($object['Attribute'])) {
foreach($object['Attribute'] as $i => $attribute) {
if ($attribute['object_relation'] == 'first-seen') {
// set object meta if unset
if (!isset($object['Object']['first-seen'])) {
$object['Object']['first-seen'] = $attribute['value'];
if (isset($forcedSeenOnElements['first_seen'])) {
$object['Object']['first_seen'] = $forcedSeenOnElements['first_seen'];
}
if (isset($forcedSeenOnElements['last_seen'])) {
$object['Object']['last_seen'] = $forcedSeenOnElements['last_seen'];
}
if ($applyOnAttribute) {
if (isset($object['Attribute'])) {
$attributes = $object['Attribute'];
} else {
$attributes = $this->find('first', array(
'conditions' => array('id' => $object['Object']['id']),
'contain' => array('Attribute')
))['Attribute'];
}
foreach($attributes as $i => $attribute) {
if (isset($forcedSeenOnElements['first_seen'])) {
$attributes[$i]['first_seen'] = $forcedSeenOnElements['first_seen'];
if ($attribute['object_relation'] == 'first-seen') {
$attributes[$i]['value'] = $forcedSeenOnElements['first_seen'];
}
if ($delete) {
$object['Attribute'][$i]['deleted'] = 1;
$this->Event->Attribute->save($object['Attribute'][$i]);
} elseif (isset($forcedSeenOnElements['last_seen'])) {
$attributes[$i]['last_seen'] = $forcedSeenOnElements['last_seen'];
if ($attribute['object_relation'] == 'last-seen') {
$attributes[$i]['value'] = $forcedSeenOnElements['last_seen'];
}
continue;
}
if ($attribute['object_relation'] == 'last-seen') {
// set object meta if unset
if (!isset($object['Object']['last-seen'])) {
$object['Object']['last-seen'] = $attribute['value'];
}
if ($delete) {
$object['Attribute'][$i]['deleted'] = 1;
$this->Event->Attribute->save($object['Attribute'][$i]);
}
continue;
}
}
$object['Attribute'] = $attributes;
}
return $object;
}
public function deltaMerge($object, $objectToSave, $onlyAddNewAttribute=false)
@ -648,17 +652,18 @@ class MispObject extends AppModel
}
$date = new DateTime();
$object['Object']['timestamp'] = $date->getTimestamp();
$this->setObjectSeenMetaFromAttribute($object, false);
$forcedSeenOnElements = array();
if (isset($objectToSave['Object']['first_seen'])) {
$object['Object']['first_seen'] = $objectToSave['Object']['first_seen'];
$forcedSeenOnElements['first_seen'] = $objectToSave['Object']['first_seen'];
}
if (isset($objectToSave['Object']['last_seen'])) {
$object['Object']['last_seen'] = $objectToSave['Object']['last_seen'];
$forcedSeenOnElements['last_seen'] = $objectToSave['Object']['last_seen'];
}
$object = $this->syncObjectAndAttributeSeen($object, $forcedSeenOnElements, false);
$this->save($object);
if (!$onlyAddNewAttribute) {
$checkFields = array('category', 'value', 'to_ids', 'distribution', 'sharing_group_id', 'comment', 'disable_correlation');
$checkFields = array('category', 'value', 'to_ids', 'distribution', 'sharing_group_id', 'comment', 'disable_correlation', 'first_seen', 'last_seen');
if (!empty($objectToSave['Attribute'])) {
foreach ($objectToSave['Attribute'] as $newKey => $newAttribute) {
foreach ($object['Attribute'] as $origKey => $originalAttribute) {
@ -673,18 +678,18 @@ class MispObject extends AppModel
$different = true;
}
// Set seen of object at attribute level
if (
(!array_key_exists('first_seen', $newAttribute) || is_null($newAttribute['first_seen'])) &&
(!array_key_exists('first_seen', $object['Object']) && !is_null($object['Object']['first_seen']))
) {
$newAttribute['first_seen'] = $object['Object']['first_seen'];
if (isset($forcedSeenOnElements['first_seen'])) {
$newAttribute['first_seen'] = $forcedSeenOnElements['first_seen'];
if ($newAttribute['object_relation'] == 'first-seen') {
// $newAttribute['value'] = $forcedSeenOnElements['first_seen'];
}
$different = true;
}
if (
(!array_key_exists('last_seen', $newAttribute) || is_null($newAttribute['last_seen'])) &&
(!array_key_exists('last_seen', $object['Object']) && !is_null($object['Object']['last_seen']))
) {
$newAttribute['last_seen'] = $object['Object']['last_seen'];
if (isset($forcedSeenOnElements['last_seen'])) {
$newAttribute['last_seen'] = $forcedSeenOnElements['last_seen'];
if ($newAttribute['object_relation'] == 'last-seen') {
// $newAttribute['value'] = $forcedSeenOnElements['last_seen'];
}
$different = true;
}
}
@ -717,17 +722,17 @@ class MispObject extends AppModel
$newAttribute['event_id'] = $object['Object']['event_id'];
$newAttribute['object_id'] = $object['Object']['id'];
// Set seen of object at attribute level
if (
(!array_key_exists('first_seen', $newAttribute) || is_null($newAttribute['first_seen'])) &&
(!array_key_exists('first_seen', $object['Object']) && !is_null($object['Object']['first_seen']))
) {
$newAttribute['first_seen'] = $object['Object']['first_seen'];
if (isset($forcedSeenOnElements['first_seen'])) {
$newAttribute['first_seen'] = $forcedSeenOnElements['first_seen'];
if ($newAttribute['object_relation'] == 'first-seen') {
$newAttribute['value'] = $forcedSeenOnElements['first_seen'];
}
}
if (
(!array_key_exists('last_seen', $newAttribute) || is_null($newAttribute['last_seen'])) &&
(!array_key_exists('last_seen', $object['Object']) && !is_null($object['Object']['last_seen']))
) {
$newAttribute['last_seen'] = $object['Object']['last_seen'];
if (isset($forcedSeenOnElements['last_seen'])) {
$newAttribute['last_seen'] = $forcedSeenOnElements['last_seen'];
if ($newAttribute['object_relation'] == 'last-seen') {
$newAttribute['value'] = $forcedSeenOnElements['last_seen'];
}
}
if (!isset($newAttribute['timestamp'])) {
$newAttribute['distribution'] = Configure::read('MISP.default_attribute_distribution');
@ -746,33 +751,31 @@ class MispObject extends AppModel
}
} else { // we only add the new attribute
$newAttribute = $objectToSave['Attribute'][0];
if ($newAttribute['object_relation'] != 'last-seen' && $newAttribute['object_relation'] != 'first-seen') { // fs/ls should be added in the object's meta
$this->Event->Attribute->create();
$newAttribute['event_id'] = $object['Object']['event_id'];
$newAttribute['object_id'] = $object['Object']['id'];
// Set seen of object at attribute level
if (
(!array_key_exists('first_seen', $newAttribute) || is_null($newAttribute['first_seen'])) &&
(!array_key_exists('first_seen', $object['Object']) && !is_null($object['Object']['first_seen']))
) {
$newAttribute['first_seen'] = $object['Object']['first_seen'];
}
if (
(!array_key_exists('last_seen', $newAttribute) || is_null($newAttribute['last_seen'])) &&
(!array_key_exists('last_seen', $object['Object']) && !is_null($object['Object']['last_seen']))
) {
$newAttribute['last_seen'] = $object['Object']['last_seen'];
$different = true;
}
if (!isset($newAttribute['timestamp'])) {
$newAttribute['distribution'] = Configure::read('MISP.default_attribute_distribution');
if ($newAttribute['distribution'] == 'event') {
$newAttribute['distribution'] = 5;
}
}
$saveAttributeResult = $this->Attribute->saveAttributes(array($newAttribute));
return $saveAttributeResult ? $this->id : $this->validationErrors;
$this->Event->Attribute->create();
$newAttribute['event_id'] = $object['Object']['event_id'];
$newAttribute['object_id'] = $object['Object']['id'];
// Set seen of object at attribute level
if (
(!array_key_exists('first_seen', $newAttribute) || is_null($newAttribute['first_seen'])) &&
(!array_key_exists('first_seen', $object['Object']) && !is_null($object['Object']['first_seen']))
) {
$newAttribute['first_seen'] = $object['Object']['first_seen'];
}
if (
(!array_key_exists('last_seen', $newAttribute) || is_null($newAttribute['last_seen'])) &&
(!array_key_exists('last_seen', $object['Object']) && !is_null($object['Object']['last_seen']))
) {
$newAttribute['last_seen'] = $object['Object']['last_seen'];
$different = true;
}
if (!isset($newAttribute['timestamp'])) {
$newAttribute['distribution'] = Configure::read('MISP.default_attribute_distribution');
if ($newAttribute['distribution'] == 'event') {
$newAttribute['distribution'] = 5;
}
}
$saveAttributeResult = $this->Attribute->saveAttributes(array($newAttribute));
return $saveAttributeResult ? $this->id : $this->validationErrors;
}
return $this->id;
}

View File

@ -178,6 +178,19 @@ function build_object_template(obj) {
return html;
}
function contain_seen_attribute(obj) {
if (obj['Attribute'] === undefined) {
return false;
}
for (var i = 0; i < obj['Attribute'].length; i++) {
var attribute = obj['Attribute'][i];
if (attribute['contentType'] == 'first-seen' || attribute['contentType'] == 'last-seen') {
return true;
}
}
return false;
}
function reflect_change(onIndex, itemType, itemId, item) {
if (onIndex) {
updateIndex(scope_id, 'event'); // MISP function
@ -254,7 +267,11 @@ function fetch_form_and_submit(itemType, item, seenType, value, reflect, callbac
cache: false,
success:function (data, textStatus) {
if (reflect) {
reflect_change(false, itemType, item.id, item);
if (contain_seen_attribute(item)) {
reflect_change(true, itemType, item.id, item);
} else {
reflect_change(false, itemType, item.id, item);
}
}
form.remove()
},