mirror of https://github.com/MISP/MISP
303 lines
12 KiB
PHP
303 lines
12 KiB
PHP
<?php
|
|
|
|
App::uses('AppModel', 'Model');
|
|
|
|
class ObjectReference extends AppModel
|
|
{
|
|
public $actsAs = array(
|
|
'Containable',
|
|
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
|
|
'userModel' => 'User',
|
|
'userKey' => 'user_id',
|
|
'change' => 'full'),
|
|
);
|
|
|
|
public $belongsTo = array(
|
|
'Object' => array(
|
|
'className' => 'MispObject',
|
|
'foreignKey' => 'object_id'
|
|
),
|
|
'ReferencedObject' => array(
|
|
'className' => 'MispObject',
|
|
'foreignKey' => false,
|
|
'conditions' => array(
|
|
'ReferencedObject.id' => 'ObjectReference.referenced_id',
|
|
1 => 'ObjectReference.referenced_type'
|
|
),
|
|
),
|
|
'ReferencedAttribute' => array(
|
|
'className' => 'Attribute',
|
|
'foreignKey' => false,
|
|
'conditions' => array(
|
|
'ReferencedAttribute.id' => 'ObjectReference.referenced_id',
|
|
0 => 'ObjectReference.referenced_type'
|
|
),
|
|
)
|
|
);
|
|
|
|
|
|
public $validate = array(
|
|
);
|
|
|
|
public function beforeValidate($options = array())
|
|
{
|
|
parent::beforeValidate();
|
|
if (empty($this->data['ObjectReference']['uuid'])) {
|
|
$this->data['ObjectReference']['uuid'] = CakeText::uuid();
|
|
}
|
|
$date = new DateTime();
|
|
$this->data['ObjectReference']['timestamp'] = $date->getTimestamp();
|
|
if (!isset($this->data['ObjectReference']['comment'])) {
|
|
$this->data['ObjectReference']['comment'] = '';
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function afterSave($created, $options = array())
|
|
{
|
|
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_object_reference_notifications_enable');
|
|
$kafkaTopic = Configure::read('Plugin.Kafka_object_reference_notifications_topic');
|
|
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_object_reference_notifications_enable') && !empty($kafkaTopic);
|
|
if ($pubToZmq || $pubToKafka) {
|
|
$object_reference = $this->find('first', array(
|
|
'conditions' => array('ObjectReference.id' => $this->id),
|
|
'recursive' => -1
|
|
));
|
|
$action = $created ? 'add' : 'edit';
|
|
if (!empty($this->data['ObjectReference']['deleted'])) {
|
|
$action = 'soft-delete';
|
|
}
|
|
if ($pubToZmq) {
|
|
$pubSubTool = $this->getPubSubTool();
|
|
$pubSubTool->object_reference_save($object_reference, $action);
|
|
}
|
|
if ($pubToKafka) {
|
|
$kafkaPubTool = $this->getKafkaPubTool();
|
|
$kafkaPubTool->publishJson($kafkaTopic, $object_reference, $action);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function updateTimestamps($id, $objectReference = false)
|
|
{
|
|
if (!$objectReference) {
|
|
$objectReference = $this->find('first', array(
|
|
'recursive' => -1,
|
|
'conditions' => array('ObjectReference.id' => $id),
|
|
'fields' => array('event_id', 'object_id')
|
|
));
|
|
}
|
|
if (empty($objectReference)) {
|
|
return false;
|
|
}
|
|
if (!isset($objectReference['ObjectReference'])) {
|
|
$objectReference = array('ObjectReference' => $objectReference);
|
|
}
|
|
$this->Object->updateTimestamp($objectReference['ObjectReference']['object_id']);
|
|
$this->Object->Event->unpublishEvent($objectReference['ObjectReference']['event_id']);
|
|
}
|
|
|
|
public function smartDelete($id, $hard = false)
|
|
{
|
|
if ($hard) {
|
|
$result = $this->delete($id);
|
|
if ($result) {
|
|
$this->updateTimestamps($id);
|
|
}
|
|
return $result;
|
|
} else {
|
|
$reference = $this->find('first', array(
|
|
'conditions' => array('ObjectReference.id' => $id),
|
|
'recursive' => -1
|
|
));
|
|
if (empty($reference)) {
|
|
return array('Invalid object reference.');
|
|
}
|
|
$reference['ObjectReference']['deleted'] = 1;
|
|
$result = $this->save($reference);
|
|
if ($result) {
|
|
$this->updateTimestamps($id);
|
|
return true;
|
|
}
|
|
return $this->validationErrors;
|
|
}
|
|
}
|
|
|
|
public function smartSave($objectReference, $eventId)
|
|
{
|
|
$sides = array('object', 'referenced');
|
|
$data = array();
|
|
foreach ($sides as $side) {
|
|
$data[$side] = $this->Object->find('first', array(
|
|
'conditions' => array(
|
|
'Object.uuid' => $objectReference[$side . '_uuid'],
|
|
'Object.event_id' => $eventId
|
|
),
|
|
'recursive' => -1,
|
|
'fields' => array('Object.id')
|
|
));
|
|
if (empty($data[$side]) && $side == 'referenced') {
|
|
$data[$side] = $this->Attribute->find('first', array(
|
|
'conditions' => array(
|
|
'Attribute.uuid' => $objectReference[$side . '_uuid'],
|
|
'Attribute.event_id' => $eventId
|
|
),
|
|
'recursive' => -1,
|
|
'fields' => array('Attribute.id')
|
|
));
|
|
$referenced_id = $data[$side]['Attribute']['id'];
|
|
$referenced_type = 0;
|
|
} elseif (!empty($data[$side]) && $side == 'referenced') {
|
|
$referenced_id = $data[$side]['Object']['id'];
|
|
$referenced_type = 1;
|
|
} elseif (!empty($data[$side]) && $side = 'object') {
|
|
$object_id = $data[$side]['Object']['id'];
|
|
} else {
|
|
return 'Invalid ' . $side . ' uuid';
|
|
}
|
|
}
|
|
$this->create();
|
|
$objectReference['referenced_type'] = $referenced_type;
|
|
$objectReference['referenced_id'] = $referenced_id;
|
|
$objectReference['object_id'] = $object_id;
|
|
$objectReference['event_id'] = $eventId;
|
|
$result = $this->save(array('ObjectReference' => $objectReference));
|
|
if (!$result) {
|
|
return $this->validationErrors;
|
|
} else {
|
|
$this->updateTimestamps($this->id, $objectReference);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function captureReference($reference, $eventId, $user, $log = false)
|
|
{
|
|
if ($log == false) {
|
|
$log = ClassRegistry::init('Log');
|
|
}
|
|
if (isset($reference['uuid'])) {
|
|
$existingReference = $this->find('first', array(
|
|
'conditions' => array('ObjectReference.uuid' => $reference['uuid']),
|
|
'recursive' => -1
|
|
));
|
|
if (!empty($existingReference)) {
|
|
// ObjectReference not newer than existing one
|
|
if (isset($reference['timestamp']) && $reference['timestamp'] <= $existingReference['ObjectReference']['timestamp']) {
|
|
return true;
|
|
}
|
|
$fieldsToUpdate = array('timestamp', 'relationship_type', 'comment', 'deleted');
|
|
foreach ($fieldsToUpdate as $field) {
|
|
if (isset($reference[$field])) {
|
|
$existingReference['ObjectReference'][$field] = $reference[$field];
|
|
}
|
|
}
|
|
$result = $this->save($existingReference);
|
|
if ($result) {
|
|
return true;
|
|
} else {
|
|
return $this->validationErrors;
|
|
}
|
|
}
|
|
}
|
|
if (isset($reference['source_uuid'])) {
|
|
$conditions = array('Object.uuid' => $reference['source_uuid']);
|
|
} elseif (isset($reference['object_uuid'])) {
|
|
$conditions = array('Object.uuid' => $reference['object_uuid']);
|
|
} elseif (isset($reference['object_id'])) {
|
|
$conditions = array('Object.id' => $reference['object_id']);
|
|
} else {
|
|
return true;
|
|
}
|
|
$sourceObject = $this->Object->find('first', array(
|
|
'recursive' => -1,
|
|
'conditions' => $conditions
|
|
));
|
|
if (isset($reference['referenced_uuid'])) {
|
|
$conditions[0] = array('Attribute.uuid' => $reference['referenced_uuid']);
|
|
$conditions[1] = array('Object.uuid' => $reference['referenced_uuid']);
|
|
} elseif (isset($reference['object_id'])) {
|
|
if ($reference['referenced_type'] == 1) {
|
|
$conditions[0] = array('Attribute.id' => $reference['referenced_id']);
|
|
$conditions[1] = array('Object.id' => $reference['referenced_id']);
|
|
} else {
|
|
$conditions = false;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
if ($conditions) {
|
|
$referencedObject = $this->Object->find('first', array(
|
|
'recursive' => -1,
|
|
'conditions' => $conditions[1]
|
|
));
|
|
}
|
|
if (empty($referencedObject)) {
|
|
$referencedObject = $this->Object->Attribute->find('first', array(
|
|
'recursive' => -1,
|
|
'conditions' => $conditions[0]
|
|
));
|
|
if (empty($referencedObject)) {
|
|
return true;
|
|
}
|
|
$referenced_type = 0;
|
|
} else {
|
|
$referenced_type = 1;
|
|
}
|
|
$referenced_type_name = array('Attribute', 'Object')[$referenced_type];
|
|
if (!isset($sourceObject['Object']) || $sourceObject['Object']['event_id'] != $eventId) {
|
|
return true;
|
|
}
|
|
if ($referencedObject[$referenced_type_name]['event_id'] != $eventId) {
|
|
return true;
|
|
}
|
|
$this->create();
|
|
unset($reference['id']);
|
|
$reference['referenced_type'] = $referenced_type;
|
|
$reference['object_id'] = $sourceObject['Object']['id'];
|
|
$reference['referenced_id'] = $referencedObject[$referenced_type_name]['id'];
|
|
$reference['referenced_uuid'] = $referencedObject[$referenced_type_name]['uuid'];
|
|
$reference['object_uuid'] = $sourceObject['Object']['uuid'];
|
|
$reference['event_id'] = $eventId;
|
|
$result = $this->save(array('ObjectReference' => $reference));
|
|
return true;
|
|
}
|
|
|
|
public function getReferencedInfo($referencedUuid, $object, $strict = true)
|
|
{
|
|
$referenced_type = 1;
|
|
$target_object = $this->Object->find('first', array(
|
|
'conditions' => array('Object.uuid' => $referencedUuid, 'Object.deleted' => 0),
|
|
'recursive' => -1,
|
|
'fields' => array('Object.id', 'Object.uuid', 'Object.event_id')
|
|
));
|
|
if (!empty($target_object)) {
|
|
$referenced_id = $target_object['Object']['id'];
|
|
$referenced_uuid = $target_object['Object']['uuid'];
|
|
if ($target_object['Object']['event_id'] != $object['Event']['id']) {
|
|
throw new NotFoundException('Invalid target. Target has to be within the same event.');
|
|
}
|
|
} else {
|
|
$target_attribute = $this->Object->Attribute->find('first', array(
|
|
'conditions' => array('Attribute.uuid' => $referencedUuid, 'Attribute.deleted' => 0),
|
|
'recursive' => -1,
|
|
'fields' => array('Attribute.id', 'Attribute.uuid', 'Attribute.event_id')
|
|
));
|
|
if (empty($target_attribute)) {
|
|
if ($strict) {
|
|
throw new NotFoundException('Invalid target.');
|
|
} else {
|
|
return array(0, 0, 0);
|
|
}
|
|
}
|
|
if ($target_attribute['Attribute']['event_id'] != $object['Event']['id']) {
|
|
throw new NotFoundException('Invalid target. Target has to be within the same event.');
|
|
}
|
|
$referenced_id = $target_attribute['Attribute']['id'];
|
|
$referenced_uuid = $target_attribute['Attribute']['uuid'];
|
|
$referenced_type = 0;
|
|
}
|
|
return array($referenced_id, $referenced_uuid, $referenced_type);
|
|
}
|
|
}
|