Merge branch 'fix-update-tags-on-attribute-edit' into 2.4

pull/6144/head
mokaddem 2020-07-27 08:20:51 +02:00
commit 72928cd6a2
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
8 changed files with 163 additions and 48 deletions

View File

@ -881,10 +881,16 @@ class AttributesController extends AppController
throw new NotFoundException(__('Invalid Event.'));
}
if ($existingAttribute['Attribute']['object_id']) {
$result = $this->Attribute->save($this->request->data, array('fieldList' => $this->Attribute->editableFieds));
$result = $this->Attribute->save($this->request->data, array('fieldList' => $this->Attribute->editableFields));
if ($result) {
$this->Attribute->AttributeTag->handleAttributeTags($this->Auth->user(), $this->request->data['Attribute'], $event['Event']['id'], $capture=true);
}
$this->Attribute->Object->updateTimestamp($existingAttribute['Attribute']['object_id']);
} else {
$result = $this->Attribute->save($this->request->data, array('fieldList' => $this->Attribute->editableFieds));
$result = $this->Attribute->save($this->request->data);
if ($result) {
$this->Attribute->AttributeTag->handleAttributeTags($this->Auth->user(), $this->request->data['Attribute'], $event['Event']['id'], $capture=true);
}
if ($this->request->is('ajax')) {
$this->autoRender = false;
if ($result) {
@ -908,20 +914,22 @@ class AttributesController extends AppController
$this->Attribute->Object->save($object);
}
}
if ($this->_isRest() || $this->response->type() === 'application/json') {
$saved_attribute = $this->Attribute->find('first', array(
'conditions' => array('id' => $this->Attribute->id),
'recursive' => -1,
'fields' => $this->Attribute->defaultFields
));
$response = array('response' => array('Attribute' => $saved_attribute['Attribute']));
$this->set('response', $response);
if ($this->response->type() === 'application/json') {
$this->render('/Attributes/json/view');
} else {
$this->render('view');
}
return;
if ($this->_isRest()) {
$saved_attribute = $this->Attribute->find('first', array(
'conditions' => array('id' => $this->Attribute->id),
'recursive' => -1,
'contain' => array('AttributeTag' => array('Tag'))
));
if ($this->response->type() === 'application/json') {
$type = 'json';
} else {
$type = 'xml';
}
App::uses(strtoupper($type) . 'ConverterTool', 'Tools');
$tool = strtoupper($type) . 'ConverterTool';
$converter = new $tool();
$saved_attribute = $converter->convertAttribute($saved_attribute, true);
return $this->RestResponse->viewData($saved_attribute, $type);
} else {
$this->redirect(array('controller' => 'events', 'action' => 'view', $eventId));
}

View File

@ -420,7 +420,7 @@ class ObjectsController extends AppController
unset($this->request->data['Object']);
}
$objectToSave = $this->MispObject->attributeCleanup($this->request->data);
$objectToSave = $this->MispObject->deltaMerge($object, $objectToSave, $onlyAddNewAttribute);
$objectToSave = $this->MispObject->deltaMerge($object, $objectToSave, $onlyAddNewAttribute, $this->Auth->user());
$error_message = __('Object could not be saved.');
if (!is_numeric($objectToSave)){
$object_validation_errors = array();
@ -581,7 +581,7 @@ class ObjectsController extends AppController
$event['Event']['timestamp'] = $date->getTimestamp();
$event['Event']['published'] = 0;
if ($seen_changed) {
$this->MispObject->Attribute->saveAttributes($object['Attribute']);
$this->MispObject->Attribute->saveAttributes($object['Attribute'], $this->Auth->user());
}
$this->MispObject->Event->save($event, array('fieldList' => array('published', 'timestamp', 'info')));
return $this->RestResponse->saveSuccessResponse('Objects', 'edit', $id, false, 'Field updated');

View File

@ -11,6 +11,24 @@ class JSONConverterTool
return ']}' . PHP_EOL;
}
public function convertAttribute($attribute, $raw = false)
{
$toRearrange = array('AttributeTag');
foreach ($toRearrange as $object) {
if (isset($attribute[$object])) {
$attribute['Attribute'][$object] = $attribute[$object];
unset($attribute[$object]);
}
}
// Submit as list to the attribute cleaner but obtain the only attribute
$attribute['Attribute'] = $this->__cleanAttributes(array($attribute['Attribute']))[0];
if ($raw) {
return $attribute;
}
return json_encode($attribute, JSON_PRETTY_PRINT);
}
public function convertObject($object, $isSiteAdmin = false, $raw = false)
{
$toRearrange = array('SharingGroup', 'Attribute', 'ShadowAttribute', 'Event');

View File

@ -40,7 +40,7 @@ class Attribute extends AppModel
'id', 'event_id', 'object_id', 'object_relation', 'category', 'type', 'value', 'to_ids', 'uuid', 'timestamp', 'distribution', 'sharing_group_id', 'comment', 'deleted', 'disable_correlation', 'first_seen', 'last_seen'
);
public $editableFieds = array('timestamp', 'category', 'value', 'value1', 'value2', 'to_ids', 'comment', 'distribution', 'sharing_group_id', 'deleted', 'disable_correlation', 'first_seen', 'last_seen');
public $editableFields = array('timestamp', 'category', 'value', 'value1', 'value2', 'to_ids', 'comment', 'distribution', 'sharing_group_id', 'deleted', 'disable_correlation', 'first_seen', 'last_seen');
public $distributionDescriptions = array(
0 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "This setting will only allow members of your organisation on this server to see it."),
@ -3712,7 +3712,7 @@ class Attribute extends AppModel
}
}
public function saveAttributes($attributes)
public function saveAttributes($attributes, $user)
{
$defaultDistribution = 5;
if (Configure::read('MISP.default_attribute_distribution') != null) {
@ -3732,7 +3732,12 @@ class Attribute extends AppModel
}
unset($attribute['Attachment']);
$this->create();
$saveResult = $saveResult && $this->save($attribute);
$currentSave = $this->save($attribute);
$saveResult = $saveResult && $currentSave;
if ($currentSave) {
$attribute['id'] = $this->id;
$this->AttributeTag->handleAttributeTags($user, $attribute, $attribute['event_id'], $capture=true);
}
}
return $saveResult;
}
@ -4267,25 +4272,11 @@ class Attribute extends AppModel
$attribute['distribution'] = 5;
}
}
$fieldList = array(
'event_id',
'category',
'type',
'value',
'value1',
'value2',
'to_ids',
'uuid',
'revision',
'distribution',
'timestamp',
'comment',
'sharing_group_id',
'deleted',
'disable_correlation',
'first_seen',
'last_seen'
);
$fieldList = $this->editableFields;
if (empty($existingAttribute)) {
$addableFieldList = array('event_id', 'type', 'uuid');
$fieldList = array_merge($fieldList, $addableFieldList);
}
if ($objectId) {
$fieldList[] = 'object_id';
$fieldList[] = 'object_relation';
@ -4317,8 +4308,9 @@ class Attribute extends AppModel
foreach ($attribute['Tag'] as $tag) {
$tag_id = $this->AttributeTag->Tag->captureTag($tag, $user);
if ($tag_id) {
$tag['id'] = $tag_id;
// fix the IDs here
$this->AttributeTag->attachTagToAttribute($this->id, $attribute['event_id'], $tag_id);
$this->AttributeTag->handleAttributeTag($this->id, $attribute['event_id'], $tag);
} else {
// If we couldn't attach the tag it is most likely because we couldn't create it - which could have many reasons
// However, if a tag couldn't be added, it could also be that the user is a tagger but not a tag editor

View File

@ -84,6 +84,44 @@ class AttributeTag extends AppModel
{
$this->delete($id);
}
/**
* handleAttributeTags
*
* @param array $attribute
* @param int $event_id
* @param bool $capture
* @return void
*/
public function handleAttributeTags($user, array $attribute, $event_id, $capture = false)
{
if ($user['Role']['perm_tagger']) {
if (isset($attribute['Tag'])) {
foreach ($attribute['Tag'] as $tag) {
if (!isset($tag['id'])) {
if ($capture) {
$tag_id = $this->Tag->captureTag($tag, $user);
} else {
$tag_id = $this->Tag->lookupTagIdFromName($tag['name']);
}
$tag['id'] = $tag_id;
}
if ($tag['id'] > 0) {
$this->handleAttributeTag($attribute['id'], $event_id, $tag);
}
}
}
}
}
public function handleAttributeTag($attribute_id, $event_id, $tag)
{
if (empty($tag['deleted'])) {
$this->attachTagToAttribute($attribute_id, $event_id, $tag['id']);
} else {
$this->detachTagFromAttribute($attribute_id, $event_id, $tag['id']);
}
}
public function attachTagToAttribute($attribute_id, $event_id, $tag_id)
{
@ -103,6 +141,26 @@ class AttributeTag extends AppModel
return true;
}
public function detachTagFromAttribute($attribute_id, $event_id, $tag_id)
{
$existingAssociation = $this->find('first', array(
'recursive' => -1,
'conditions' => array(
'tag_id' => $tag_id,
'event_id' => $event_id,
'attribute_id' => $attribute_id
)
));
if (!empty($existingAssociation)) {
$result = $this->delete($existingAssociation['AttributeTag']['id']);
if ($result) {
return true;
}
}
return false;
}
// This function help mirroring the tags at attribute level. It will delete tags that are not present on the remote attribute
public function pruneOutdatedAttributeTagsFromSync($newerTags, $originalAttributeTags)
{

View File

@ -3942,7 +3942,8 @@ class Event extends AppModel
$tag_id = $this->EventTag->Tag->captureTag($tag, $user);
if ($tag_id) {
$nothingToChange = false;
$result = $this->EventTag->attachTagToEvent($this->id, $tag_id, $nothingToChange);
$tag['id'] = $tag_id;
$result = $this->EventTag->handleEventTag($this->id, $tag, $nothingToChange);
if ($result && !$nothingToChange) {
$changed = true;
}

View File

@ -110,6 +110,16 @@ class EventTag extends AppModel
return $eventIDs;
}
public function handleEventTag($event_id, $tag, &$nothingToChange = false)
{
if (empty($tag['deleted'])) {
$result = $this->attachTagToEvent($event_id, $tag['id'], $nothingToChange);
} else {
$result = $this->detachTagFromEvent($event_id, $tag['id'], $nothingToChange);
}
return $result;
}
public function attachTagToEvent($event_id, $tag_id, &$nothingToChange = false)
{
$existingAssociation = $this->find('first', array(
@ -130,6 +140,27 @@ class EventTag extends AppModel
return true;
}
public function detachTagFromEvent($event_id, $tag_id, &$nothingToChange = false)
{
$existingAssociation = $this->find('first', array(
'recursive' => -1,
'conditions' => array(
'tag_id' => $tag_id,
'event_id' => $event_id
)
));
if (!empty($existingAssociation)) {
$result = $this->delete($existingAssociation['EventTag']['id']);
if ($result) {
return true;
}
} else {
$nothingToChange = true;
}
return false;
}
public function getSortedTagList($context = false)
{
$conditions = array();

View File

@ -381,7 +381,7 @@ class MispObject extends AppModel
$object['Attribute'][$k]['last_seen'] = $object['Object']['last_seen'];
}
}
$this->Attribute->saveAttributes($object['Attribute']);
$this->Attribute->saveAttributes($object['Attribute'], $user);
} else {
$result = $this->validationErrors;
}
@ -770,7 +770,7 @@ class MispObject extends AppModel
return $object;
}
public function deltaMerge($object, $objectToSave, $onlyAddNewAttribute=false)
public function deltaMerge($object, $objectToSave, $onlyAddNewAttribute=false, $user)
{
if (!isset($objectToSave['Object'])) {
$dataToBackup = array('ObjectReferences', 'Attribute', 'ShadowAttribute');
@ -849,7 +849,10 @@ class MispObject extends AppModel
$newAttribute['event_id'] = $object['Object']['event_id'];
$newAttribute['object_id'] = $object['Object']['id'];
$newAttribute['timestamp'] = $date->getTimestamp();
$result = $this->Event->Attribute->save(array('Attribute' => $newAttribute), array('fieldList' => $this->Attribute->editableFieds));
$result = $this->Event->Attribute->save(array('Attribute' => $newAttribute), array('fieldList' => $this->Attribute->editableFields));
if ($result) {
$this->Event->Attribute->AttributeTag->handleAttributeTags($user, $newAttribute, $newAttribute['event_id'], $capture=true);
}
}
unset($object['Attribute'][$origKey]);
continue 2;
@ -878,13 +881,17 @@ class MispObject extends AppModel
$newAttribute['distribution'] = 5;
}
}
$this->Event->Attribute->save($newAttribute);
$saveResult = $this->Event->Attribute->save($newAttribute);
if ($saveResult) {
$newAttribute['id'] = $this->Event->Attribute->id;
$this->Event->Attribute->AttributeTag->handleAttributeTags($user, $newAttribute, $newAttribute['event_id'], $capture=true);
}
$attributeArrays['add'][] = $newAttribute;
unset($objectToSave['Attribute'][$newKey]);
}
foreach ($object['Attribute'] as $origKey => $originalAttribute) {
$originalAttribute['deleted'] = 1;
$this->Event->Attribute->save($originalAttribute, array('fieldList' => $this->Attribute->editableFieds));
$this->Event->Attribute->save($originalAttribute, array('fieldList' => $this->Attribute->editableFields));
}
}
} else { // we only add the new attribute
@ -912,7 +919,7 @@ class MispObject extends AppModel
$newAttribute['distribution'] = 5;
}
}
$saveAttributeResult = $this->Attribute->saveAttributes(array($newAttribute));
$saveAttributeResult = $this->Attribute->saveAttributes(array($newAttribute), $user);
return $saveAttributeResult ? $this->id : $this->validationErrors;
}
return $this->id;