new: [objects] pass the /breakOnDuplicate:1 flag to the /objects/add endpoint to deduplicate

- returns an error if the object already exists
  - objects of the same template_uuid are compared
  - non deleted attributes only
  - type + category + value + object_relation tuple is compared
pull/5615/head
iglocska 2020-02-10 14:30:34 +01:00
parent 934c828192
commit 4ea3612dfc
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
2 changed files with 44 additions and 2 deletions

View File

@ -238,6 +238,7 @@ class ObjectsController extends AppController
$this->request->data['Attribute'] = $this->request->data['Object']['Attribute'];
unset($this->request->data['Object']['Attribute']);
}
$breakOnDuplicate = !empty($this->request->data['Object']['breakOnDuplicate']) || !empty($this->params['named']['breakOnDuplicate']);
$object = $this->MispObject->attributeCleanup($this->request->data);
// we pre-validate the attributes before we create an object at this point
// This allows us to stop the process and return an error (API) or return
@ -283,7 +284,7 @@ class ObjectsController extends AppController
}
if (empty($error)) {
unset($object['Object']['id']);
$result = $this->MispObject->saveObject($object, $eventId, $template, $this->Auth->user(), $errorBehaviour = 'halt');
$result = $this->MispObject->saveObject($object, $eventId, $template, $this->Auth->user(), 'halt', $breakOnDuplicate);
if (is_numeric($result)) {
$this->MispObject->Event->unpublishEvent($eventId);
} else {

View File

@ -203,8 +203,49 @@ class MispObject extends AppModel
}
}
public function saveObject($object, $eventId, $template = false, $user, $errorBehaviour = 'drop')
public function checkForDuplicateObjects($object, $eventId)
{
$newObjectAttributes = array();
$existingObjectAttributes = array();
foreach ($object['Attribute'] as $attribute) {
$newObjectAttributes[] = hash('sha256', $attribute['object_relation'] . $attribute['category'] . $attribute['type'] . $attribute['value']);
}
$newObjectAttributeCount = count($newObjectAttributes);
$existingObjects = $this->find('all', array(
'recursive' => -1,
'contain' => array(
'Attribute' => array(
'fields' => array('value', 'type', 'category', 'object_relation'),
'conditions' => array('Attribute.deleted' => 0)
)
),
'fields' => array('template_uuid'),
'conditions' => array('template_uuid' => $object['Object']['template_uuid'], 'Object.deleted' => 0)
));
$oldObjects = array();
foreach ($existingObjects as $k => $existingObject) {
if (!empty($existingObject['Attribute']) && $newObjectAttributeCount == count($existingObject['Attribute'])) {
foreach ($existingObject['Attribute'] as $existingAttribute) {
$oldObjects[$k][] = hash('sha256',
$attribute['object_relation'] . $existingAttribute['category'] . $existingAttribute['type'] . $existingAttribute['value']
);
}
}
}
foreach ($oldObjects as $k => $object) {
if (empty(array_diff($object, $newObjectAttributes))) {
return true;
}
}
return false;
}
public function saveObject($object, $eventId, $template = false, $user, $errorBehaviour = 'drop', $breakOnDuplicate = false)
{
if ($breakOnDuplicate) {
$duplicate = $this->checkForDuplicateObjects($object, $eventId);
return array('value' => array('Duplicate object found. Since breakOnDuplicate is set the object will not be added.'));
}
$this->create();
$templateFields = array(
'name' => 'name',