mirror of https://github.com/MISP/MISP
Merge branch 'fix-update-tags-on-attribute-edit' into 2.4
commit
72928cd6a2
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue