2017-06-13 12:08:26 +02:00
< ? php
App :: uses ( 'AppModel' , 'Model' );
2018-07-19 11:48:22 +02:00
class MispObject extends AppModel
{
public $name = 'Object' ;
public $alias = 'Object' ;
2017-07-05 14:25:09 +02:00
2018-07-19 11:48:22 +02:00
public $useTable = 'objects' ;
2017-07-06 15:04:01 +02:00
2018-07-19 11:48:22 +02:00
public $actsAs = array (
'Containable' ,
2019-02-10 13:08:12 +01:00
'SysLogLogable.SysLogLogable' => array ( // TODO Audit, logable
2018-07-19 11:48:22 +02:00
'userModel' => 'User' ,
'userKey' => 'user_id' ,
'change' => 'full' ),
);
2017-07-05 14:25:09 +02:00
2018-07-19 11:48:22 +02:00
public $belongsTo = array (
'Event' => array (
'className' => 'Event' ,
'foreignKey' => 'event_id'
),
'SharingGroup' => array (
'className' => 'SharingGroup' ,
'foreignKey' => 'sharing_group_id'
),
'ObjectTemplate' => array (
'className' => 'ObjectTemplate' ,
'foreignKey' => false ,
'dependent' => false ,
'conditions' => array ( 'MispObject.template_uuid' => 'ObjectTemplate.uuid' )
)
);
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
public $hasMany = array (
'Attribute' => array (
'className' => 'Attribute' ,
'dependent' => true ,
),
'ObjectReference' => array (
'className' => 'ObjectReference' ,
'dependent' => true ,
'foreignKey' => 'object_id'
),
);
2017-07-05 09:02:16 +02:00
2018-07-19 11:48:22 +02:00
public $validate = array (
2018-11-23 14:11:33 +01:00
'uuid' => array (
'uuid' => array (
'rule' => array ( 'custom' , '/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/' ),
'message' => 'Please provide a valid UUID'
),
'unique' => array (
'rule' => 'isUnique' ,
'message' => 'The UUID provided is not unique' ,
'required' => 'create'
)
)
2018-07-19 11:48:22 +02:00
);
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
public function beforeValidate ( $options = array ())
{
parent :: beforeValidate ();
if ( empty ( $this -> data [ $this -> alias ][ 'comment' ])) {
$this -> data [ $this -> alias ][ 'comment' ] = " " ;
}
// generate UUID if it doesn't exist
if ( empty ( $this -> data [ $this -> alias ][ 'uuid' ])) {
$this -> data [ $this -> alias ][ 'uuid' ] = CakeText :: uuid ();
}
// generate timestamp if it doesn't exist
if ( empty ( $this -> data [ $this -> alias ][ 'timestamp' ])) {
$date = new DateTime ();
$this -> data [ $this -> alias ][ 'timestamp' ] = $date -> getTimestamp ();
}
if ( empty ( $this -> data [ $this -> alias ][ 'template_version' ])) {
$this -> data [ $this -> alias ][ 'template_version' ] = 1 ;
}
if ( isset ( $this -> data [ $this -> alias ][ 'deleted' ]) && empty ( $this -> data [ $this -> alias ][ 'deleted' ])) {
$this -> data [ $this -> alias ][ 'deleted' ] = 0 ;
}
if ( ! isset ( $this -> data [ $this -> alias ][ 'distribution' ]) || $this -> data [ 'Object' ][ 'distribution' ] != 4 ) {
$this -> data [ 'Object' ][ 'sharing_group_id' ] = 0 ;
}
if ( ! isset ( $this -> data [ $this -> alias ][ 'distribution' ])) {
$this -> data [ 'Object' ][ 'distribution' ] = 5 ;
}
return true ;
}
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
public function afterSave ( $created , $options = array ())
{
2019-03-05 12:24:56 +01:00
$pubToZmq = Configure :: read ( 'Plugin.ZeroMQ_enable' ) &&
Configure :: read ( 'Plugin.ZeroMQ_object_notifications_enable' ) &&
empty ( $this -> data [ 'Object' ][ 'skip_zmq' ]);
$kafkaTopic = Configure :: read ( 'Plugin.Kafka_object_notifications_topic' );
$pubToKafka = Configure :: read ( 'Plugin.Kafka_enable' ) &&
Configure :: read ( 'Plugin.Kafka_object_notifications_enable' ) &&
! empty ( $kafkaTopic ) &&
empty ( $this -> data [ 'Object' ][ 'skip_kafka' ]);
if ( $pubToZmq || $pubToKafka ) {
$object = $this -> find ( 'first' , array (
'conditions' => array ( 'Object.id' => $this -> id ),
'recursive' => - 1
));
$action = $created ? 'add' : 'edit' ;
if ( ! empty ( $this -> data [ 'Object' ][ 'deleted' ])) {
$action = 'soft-delete' ;
}
if ( $pubToZmq ) {
2018-07-19 11:48:22 +02:00
$pubSubTool = $this -> getPubSubTool ();
$pubSubTool -> object_save ( $object , $action );
}
2019-03-05 12:24:56 +01:00
if ( $pubToKafka ) {
$kafkaPubTool = $this -> getKafkaPubTool ();
$kafkaPubTool -> publishJson ( $kafkaTopic , $object , $action );
}
2018-07-19 11:48:22 +02:00
}
return true ;
}
2017-07-02 22:42:44 +02:00
2018-07-19 11:48:22 +02:00
public function beforeDelete ( $cascade = true )
{
if ( ! empty ( $this -> data [ 'Object' ][ 'id' ])) {
2019-03-05 12:24:56 +01:00
$pubToZmq = Configure :: read ( 'Plugin.ZeroMQ_enable' ) && Configure :: read ( 'Plugin.ZeroMQ_object_notifications_enable' );
$kafkaTopic = Configure :: read ( 'Plugin.Kafka_object_notifications_topic' );
$pubToKafka = Configure :: read ( 'Plugin.Kafka_enable' ) && Configure :: read ( 'Plugin.Kafka_object_notifications_enable' ) && ! empty ( $kafkaTopic );
if ( $pubToZmq || $pubToKafka ) {
2018-07-19 11:48:22 +02:00
$object = $this -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.id' => $this -> data [ 'Object' ][ 'id' ])
));
2019-03-05 12:24:56 +01:00
if ( $pubToZmq ) {
$pubSubTool = $this -> getPubSubTool ();
$pubSubTool -> object_save ( $object , 'delete' );
}
if ( $pubToKafka ) {
$kafkaPubTool = $this -> getKafkaPubTool ();
$kafkaPubTool -> publishJson ( $kafkaTopic , $object , 'delete' );
}
2018-07-19 11:48:22 +02:00
}
}
}
2017-10-27 09:10:46 +02:00
2018-07-19 11:48:22 +02:00
public function afterDelete ()
{
if ( ! empty ( $this -> data [ $this -> alias ][ 'id' ])) {
$this -> ObjectReference -> deleteAll (
array (
'ObjectReference.referenced_type' => 1 ,
'ObjectReference.referenced_id' => $this -> data [ $this -> alias ][ 'id' ],
),
false
);
}
}
2017-10-27 09:10:46 +02:00
2018-07-19 11:48:22 +02:00
public function saveObject ( $object , $eventId , $template = false , $user , $errorBehaviour = 'drop' )
{
$this -> create ();
$templateFields = array (
'name' => 'name' ,
'meta-category' => 'meta-category' ,
'description' => 'description' ,
'template_version' => 'version' ,
'template_uuid' => 'uuid'
);
if ( $template ) {
foreach ( $templateFields as $k => $v ) {
$object [ 'Object' ][ $k ] = $template [ 'ObjectTemplate' ][ $v ];
}
} else {
foreach ( $templateFields as $k => $v ) {
if ( ! isset ( $object [ 'Object' ][ $k ])) {
return 'No valid template found and object lacking template information. (' . $k . ')' ;
}
}
}
$object [ 'Object' ][ 'event_id' ] = $eventId ;
$result = false ;
if ( $this -> save ( $object )) {
$result = $this -> id ;
foreach ( $object [ 'Attribute' ] as $k => $attribute ) {
$object [ 'Attribute' ][ $k ][ 'object_id' ] = $this -> id ;
}
$this -> Attribute -> saveAttributes ( $object [ 'Attribute' ]);
} else {
$result = $this -> validationErrors ;
}
return $result ;
}
2017-09-17 12:26:06 +02:00
2018-07-19 11:48:22 +02:00
public function buildEventConditions ( $user , $sgids = false )
{
if ( $user [ 'Role' ][ 'perm_site_admin' ]) {
return array ();
}
if ( $sgids == false ) {
$sgsids = $this -> SharingGroup -> fetchAllAuthorised ( $user );
}
return array (
'OR' => array (
array (
'AND' => array (
'Event.distribution >' => 0 ,
'Event.distribution <' => 4 ,
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published' => 1 ) : array (),
),
),
array (
'AND' => array (
'Event.sharing_group_id' => $sgids ,
'Event.distribution' => 4 ,
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published' => 1 ) : array (),
)
)
)
);
}
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
public function buildConditions ( $user , $sgids = false )
{
$conditions = array ();
if ( ! $user [ 'Role' ][ 'perm_site_admin' ]) {
if ( $sgids === false ) {
$sgsids = $this -> SharingGroup -> fetchAllAuthorised ( $user );
}
$conditions = array (
'AND' => array (
'OR' => array (
array (
'AND' => array (
'Event.org_id' => $user [ 'org_id' ],
)
),
array (
'AND' => array (
$this -> buildEventConditions ( $user , $sgids ),
'OR' => array (
'Object.distribution' => array ( '1' , '2' , '3' , '5' ),
'AND ' => array (
'Object.distribution' => 4 ,
'Object.sharing_group_id' => $sgsids ,
)
)
)
)
)
)
);
}
return $conditions ;
}
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
// Method that fetches all objects
// very flexible, it's basically a replacement for find, with the addition that it restricts access based on user
// options:
// fields
// contain
// conditions
// order
// group
public function fetchObjects ( $user , $options = array ())
{
$sgsids = $this -> SharingGroup -> fetchAllAuthorised ( $user );
$attributeConditions = array ();
if ( ! $user [ 'Role' ][ 'perm_site_admin' ]) {
$attributeConditions = array (
'OR' => array (
array (
'(SELECT events.org_id FROM events WHERE events.id = Attribute.event_id)' => $user [ 'org_id' ]
),
array (
'OR' => array (
'Attribute.distribution' => array ( 1 , 2 , 3 , 5 ),
array (
'Attribute.distribution' => 4 ,
'Attribute.sharing_group_id' => $sgsids
)
)
)
)
);
}
$params = array (
'conditions' => $this -> buildConditions ( $user ),
'recursive' => - 1 ,
'contain' => array (
'Event' => array (
'fields' => array ( 'id' , 'info' , 'org_id' , 'orgc_id' ),
),
'Attribute' => array (
'conditions' => $attributeConditions ,
//'ShadowAttribute',
'AttributeTag' => array (
'Tag'
)
)
)
);
if ( empty ( $options [ 'includeAllTags' ])) {
$params [ 'contain' ][ 'Attribute' ][ 'AttributeTag' ][ 'Tag' ][ 'conditions' ][ 'exportable' ] = 1 ;
}
if ( isset ( $options [ 'contain' ])) {
$params [ 'contain' ] = array_merge_recursive ( $params [ 'contain' ], $options [ 'contain' ]);
} else {
$option [ 'contain' ][ 'Event' ][ 'fields' ] = array ( 'id' , 'info' , 'org_id' , 'orgc_id' );
}
if ( Configure :: read ( 'MISP.proposals_block_attributes' ) && isset ( $options [ 'conditions' ][ 'AND' ][ 'Attribute.to_ids' ]) && $options [ 'conditions' ][ 'AND' ][ 'Attribute.to_ids' ] == 1 ) {
$this -> Attribute -> bindModel ( array ( 'hasMany' => array ( 'ShadowAttribute' => array ( 'foreignKey' => 'old_id' ))));
$proposalRestriction = array (
'ShadowAttribute' => array (
'conditions' => array (
'AND' => array (
'ShadowAttribute.deleted' => 0 ,
'OR' => array (
'ShadowAttribute.proposal_to_delete' => 1 ,
'ShadowAttribute.to_ids' => 0
)
)
),
'fields' => array ( 'ShadowAttribute.id' )
)
);
$params [ 'contain' ] = array_merge ( $params [ 'contain' ][ 'Attribute' ], $proposalRestriction );
}
if ( isset ( $options [ 'fields' ])) {
$params [ 'fields' ] = $options [ 'fields' ];
}
if ( isset ( $options [ 'conditions' ])) {
$params [ 'conditions' ][ 'AND' ][] = $options [ 'conditions' ];
}
if ( isset ( $options [ 'order' ])) {
$params [ 'order' ] = $options [ 'order' ];
}
if ( ! isset ( $options [ 'withAttachments' ])) {
$options [ 'withAttachments' ] = false ;
} else ( $params [ 'order' ] = array ());
if ( ! isset ( $options [ 'enforceWarninglist' ])) {
$options [ 'enforceWarninglist' ] = false ;
}
if ( ! $user [ 'Role' ][ 'perm_sync' ] || ! isset ( $options [ 'deleted' ]) || ! $options [ 'deleted' ]) {
$params [ 'contain' ][ 'Attribute' ][ 'conditions' ][ 'AND' ][ 'Attribute.deleted' ] = 0 ;
}
if ( isset ( $options [ 'group' ])) {
$params [ 'group' ] = array_merge ( array ( 'Object.id' ), $options [ 'group' ]);
}
if ( Configure :: read ( 'MISP.unpublishedprivate' )) {
$params [ 'conditions' ][ 'AND' ][] = array ( 'OR' => array ( 'Event.published' => 1 , 'Event.orgc_id' => $user [ 'org_id' ]));
}
$results = $this -> find ( 'all' , $params );
if ( $options [ 'enforceWarninglist' ]) {
$this -> Warninglist = ClassRegistry :: init ( 'Warninglist' );
$warninglists = $this -> Warninglist -> fetchForEventView ();
}
$results = array_values ( $results );
$proposals_block_attributes = Configure :: read ( 'MISP.proposals_block_attributes' );
foreach ( $results as $key => $objects ) {
foreach ( $objects as $key2 => $attribute ) {
if ( $options [ 'enforceWarninglist' ] && ! $this -> Warninglist -> filterWarninglistAttributes ( $warninglists , $attribute [ 'Attribute' ], $this -> Warninglist )) {
unset ( $results [ $key ][ $key2 ]);
continue ;
}
if ( $proposals_block_attributes ) {
if ( ! empty ( $attribute [ 'ShadowAttribute' ])) {
unset ( $results [ $key ][ $key2 ]);
} else {
unset ( $results [ $key ][ $key2 ][ 'ShadowAttribute' ]);
}
}
if ( $options [ 'withAttachments' ]) {
if ( $this -> typeIsAttachment ( $attribute [ 'Attribute' ][ 'type' ])) {
$encodedFile = $this -> base64EncodeAttachment ( $attribute [ 'Attribute' ]);
$results [ $key ][ $key2 ][ 'Attribute' ][ 'data' ] = $encodedFile ;
}
}
}
}
return $results ;
}
2017-06-13 12:08:26 +02:00
2018-07-19 11:48:22 +02:00
/*
* Prepare the template form view ' s data , setting defaults , sorting elements
*/
public function prepareTemplate ( $template , $request = array ())
{
$temp = array ();
usort ( $template [ 'ObjectTemplateElement' ], function ( $a , $b ) {
return $a [ 'ui-priority' ] < $b [ 'ui-priority' ];
});
$request_rearranged = array ();
$template_object_elements = $template [ 'ObjectTemplateElement' ];
unset ( $template [ 'ObjectTemplateElement' ]);
if ( ! empty ( $request [ 'Attribute' ])) {
foreach ( $request [ 'Attribute' ] as $attribute ) {
$request_rearranged [ $attribute [ 'object_relation' ]][] = $attribute ;
}
}
foreach ( $template_object_elements as $k => $v ) {
if ( empty ( $request_rearranged [ $v [ 'object_relation' ]])) {
if ( isset ( $this -> Event -> Attribute -> typeDefinitions [ $v [ 'type' ]])) {
$v [ 'default_category' ] = $this -> Event -> Attribute -> typeDefinitions [ $v [ 'type' ]][ 'default_category' ];
$v [ 'to_ids' ] = $this -> Event -> Attribute -> typeDefinitions [ $v [ 'type' ]][ 'to_ids' ];
if ( empty ( $v [ 'categories' ])) {
$v [ 'categories' ] = array ();
foreach ( $this -> Event -> Attribute -> categoryDefinitions as $catk => $catv ) {
if ( in_array ( $v [ 'type' ], $catv [ 'types' ])) {
$v [ 'categories' ][] = $catk ;
}
}
}
$template [ 'ObjectTemplateElement' ][] = $v ;
} else {
$template [ 'warnings' ][] = 'Missing attribute type "' . $v [ 'type' ] . '" found. Omitted template element ("' . $template_object_elements [ $k ][ 'object_relation' ] . '") that would not pass validation due to this.' ;
}
} else {
foreach ( $request_rearranged [ $v [ 'object_relation' ]] as $request_item ) {
if ( isset ( $this -> Event -> Attribute -> typeDefinitions [ $v [ 'type' ]])) {
$v [ 'default_category' ] = $request_item [ 'category' ];
$v [ 'value' ] = $request_item [ 'value' ];
$v [ 'to_ids' ] = $request_item [ 'to_ids' ];
$v [ 'comment' ] = $request_item [ 'comment' ];
if ( ! empty ( $request_item [ 'uuid' ])) {
$v [ 'uuid' ] = $request_item [ 'uuid' ];
}
if ( isset ( $request_item [ 'data' ])) {
$v [ 'data' ] = $request_item [ 'data' ];
}
if ( empty ( $v [ 'categories' ])) {
$v [ 'categories' ] = array ();
foreach ( $this -> Event -> Attribute -> categoryDefinitions as $catk => $catv ) {
if ( in_array ( $v [ 'type' ], $catv [ 'types' ])) {
$v [ 'categories' ][] = $catk ;
}
}
}
2018-11-21 15:25:03 +01:00
$v [ 'disable_correlation' ] = $request_item [ 'disable_correlation' ];
2018-07-19 11:48:22 +02:00
$template [ 'ObjectTemplateElement' ][] = $v ;
} else {
$template [ 'warnings' ][] = 'Missing attribute type "' . $v [ 'type' ] . '" found. Omitted template element ("' . $template_object_elements [ $k ][ 'object_relation' ] . '") that would not pass validation due to this.' ;
}
}
}
}
return $template ;
}
2017-07-02 00:05:15 +02:00
2018-07-19 11:48:22 +02:00
/*
* Clean the attribute list up from artifacts introduced by the object form
*/
public function attributeCleanup ( $attributes )
{
if ( empty ( $attributes [ 'Attribute' ])) {
return 'No attribute data found' ;
}
foreach ( $attributes [ 'Attribute' ] as $k => $attribute ) {
if ( isset ( $attribute [ 'save' ]) && $attribute [ 'save' ] == 0 ) {
unset ( $attributes [ 'Attribute' ][ $k ]);
continue ;
}
if ( isset ( $attribute [ 'value_select' ])) {
if ( $attribute [ 'value_select' ] !== 'Enter value manually' ) {
$attributes [ 'Attribute' ][ $k ][ 'value' ] = $attribute [ 'value_select' ];
}
unset ( $attributes [ 'Attribute' ][ $k ][ 'value_select' ]);
}
if ( isset ( $attribute [ 'Attachment' ])) {
// Check if there were problems with the file upload
// only keep the last part of the filename, this should prevent directory attacks
$filename = basename ( $attribute [ 'Attachment' ][ 'name' ]);
$tmpfile = new File ( $attribute [ 'Attachment' ][ 'tmp_name' ]);
if (( isset ( $attribute [ 'Attachment' ][ 'error' ]) && $attribute [ 'Attachment' ][ 'error' ] == 0 ) ||
( ! empty ( $attribute [ 'Attachment' ][ 'tmp_name' ]) && $attribute [ 'Attachment' ][ 'tmp_name' ] != 'none' )
) {
if ( ! is_uploaded_file ( $tmpfile -> path )) {
throw new InternalErrorException ( 'PHP says file was not uploaded. Are you attacking me?' );
}
} else {
return 'Issues with the file attachment for the ' . $attribute [ 'object_relation' ] . ' attribute. The error code returned is ' . $attribute [ 'Attachment' ][ 'error' ];
}
$attributes [ 'Attribute' ][ $k ][ 'value' ] = $attribute [ 'Attachment' ][ 'name' ];
unset ( $attributes [ 'Attribute' ][ $k ][ 'Attachment' ]);
$attributes [ 'Attribute' ][ $k ][ 'encrypt' ] = $attribute [ 'type' ] == 'malware-sample' ? 1 : 0 ;
$attributes [ 'Attribute' ][ $k ][ 'data' ] = base64_encode ( $tmpfile -> read ());
$tmpfile -> delete ();
$tmpfile -> close ();
}
unset ( $attributes [ 'Attribute' ][ $k ][ 'save' ]);
}
return $attributes ;
}
2017-07-02 20:32:30 +02:00
2018-07-19 11:48:22 +02:00
public function deltaMerge ( $object , $objectToSave )
{
if ( ! isset ( $objectToSave [ 'Object' ])) {
$dataToBackup = array ( 'ObjectReferences' , 'Attribute' , 'ShadowAttribute' );
$backup = array ();
foreach ( $dataToBackup as $dtb ) {
if ( isset ( $objectToSave [ $dtb ])) {
$backup [ $dtb ] = $objectToSave [ $dtb ];
unset ( $objectToSave [ $dtb ]);
}
}
$objectToSave = array ( 'Object' => $objectToSave );
foreach ( $dataToBackup as $dtb ) {
if ( isset ( $backup [ $dtb ])) {
$objectToSave [ $dtb ] = $backup [ $dtb ];
}
}
unset ( $dataToBackup );
}
$object [ 'Object' ][ 'comment' ] = $objectToSave [ 'Object' ][ 'comment' ];
$object [ 'Object' ][ 'distribution' ] = $objectToSave [ 'Object' ][ 'distribution' ];
if ( $object [ 'Object' ][ 'distribution' ] == 4 ) {
$object [ 'Object' ][ 'sharing_group_id' ] = $objectToSave [ 'Object' ][ 'sharing_group_id' ];
}
$date = new DateTime ();
$object [ 'Object' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> save ( $object );
2018-11-21 15:25:03 +01:00
$checkFields = array ( 'category' , 'value' , 'to_ids' , 'distribution' , 'sharing_group_id' , 'comment' , 'disable_correlation' );
2018-07-19 11:48:22 +02:00
foreach ( $objectToSave [ 'Attribute' ] as $newKey => $newAttribute ) {
foreach ( $object [ 'Attribute' ] as $origKey => $originalAttribute ) {
if ( ! empty ( $newAttribute [ 'uuid' ])) {
if ( $newAttribute [ 'uuid' ] == $originalAttribute [ 'uuid' ]) {
$different = false ;
foreach ( $checkFields as $f ) {
if ( $f == 'sharing_group_id' && empty ( $newAttribute [ $f ])) {
$newAttribute [ $f ] = 0 ;
}
if ( $newAttribute [ $f ] != $originalAttribute [ $f ]) {
$different = true ;
}
}
if ( $different ) {
$newAttribute [ 'id' ] = $originalAttribute [ 'id' ];
$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 (
'category' ,
'value' ,
'to_ids' ,
'distribution' ,
'sharing_group_id' ,
'comment' ,
'timestamp' ,
'object_id' ,
2018-11-21 15:25:03 +01:00
'event_id' ,
'disable_correlation'
2018-07-19 11:48:22 +02:00
));
}
unset ( $object [ 'Attribute' ][ $origKey ]);
continue 2 ;
}
}
}
$this -> Event -> Attribute -> create ();
$newAttribute [ 'event_id' ] = $object [ 'Object' ][ 'event_id' ];
$newAttribute [ 'object_id' ] = $object [ 'Object' ][ 'id' ];
2019-02-10 13:08:12 +01:00
if ( ! isset ( $newAttribute [ 'timestamp' ])) {
$newAttribute [ 'distribution' ] = Configure :: read ( 'MISP.default_attribute_distribution' );
if ( $newAttribute [ 'distribution' ] == 'event' ) {
$newAttribute [ 'distribution' ] = 5 ;
}
}
2018-07-19 11:48:22 +02:00
$this -> Event -> Attribute -> save ( $newAttribute );
$attributeArrays [ 'add' ][] = $newAttribute ;
unset ( $objectToSave [ 'Attribute' ][ $newKey ]);
}
foreach ( $object [ 'Attribute' ] as $origKey => $originalAttribute ) {
$originalAttribute [ 'deleted' ] = 1 ;
$this -> Event -> Attribute -> save ( $originalAttribute );
}
return $this -> id ;
}
2017-07-06 15:04:01 +02:00
2018-07-19 11:48:22 +02:00
public function captureObject ( $object , $eventId , $user , $log = false )
{
$this -> create ();
if ( ! isset ( $object [ 'Object' ])) {
$object = array ( 'Object' => $object );
}
if ( empty ( $log )) {
$log = ClassRegistry :: init ( 'Log' );
}
if ( isset ( $object [ 'Object' ][ 'id' ])) {
unset ( $object [ 'Object' ][ 'id' ]);
}
$object [ 'Object' ][ 'event_id' ] = $eventId ;
if ( $this -> save ( $object )) {
$this -> Event -> unpublishEvent ( $eventId );
$objectId = $this -> id ;
$partialFails = array ();
foreach ( $object [ 'Object' ][ 'Attribute' ] as $attribute ) {
$this -> Attribute -> captureAttribute ( $attribute , $eventId , $user , $objectId , $log );
}
return true ;
} else {
$log -> create ();
$log -> save ( array (
'org' => $user [ 'Organisation' ][ 'name' ],
'model' => 'Object' ,
'model_id' => 0 ,
'email' => $user [ 'email' ],
'action' => 'add' ,
'user_id' => $user [ 'id' ],
'title' => 'Object dropped due to validation for Event ' . $eventId . ' failed: ' . $object [ 'Object' ][ 'name' ],
'change' => 'Validation errors: ' . json_encode ( $this -> validationErrors ) . ' Full Object: ' . json_encode ( $attribute ),
));
}
return 'fail' ;
}
2017-08-28 09:18:40 +02:00
2018-07-19 11:48:22 +02:00
public function editObject ( $object , $eventId , $user , $log )
{
$object [ 'event_id' ] = $eventId ;
if ( isset ( $object [ 'uuid' ])) {
$existingObject = $this -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.uuid' => $object [ 'uuid' ])
));
if ( empty ( $existingObject )) {
return $this -> captureObject ( $object , $eventId , $user , $log );
} else {
if ( $existingObject [ 'Object' ][ 'event_id' ] != $eventId ) {
$log -> create ();
$log -> save ( array (
'org' => $user [ 'Organisation' ][ 'name' ],
'model' => 'Object' ,
'model_id' => 0 ,
'email' => $user [ 'email' ],
'action' => 'edit' ,
'user_id' => $user [ 'id' ],
'title' => 'Duplicate UUID found in object' ,
'change' => 'An object was blocked from being saved due to a duplicate UUID. The uuid in question is: ' . $object [ 'uuid' ] . '. This can also be due to the same object (or an object with the same UUID) existing in a different event)' ,
));
return true ;
}
if ( isset ( $object [ 'timestamp' ])) {
if ( $existingObject [ 'Object' ][ 'timestamp' ] >= $object [ 'timestamp' ]) {
return true ;
}
} else {
$date = new DateTime ();
$object [ 'timestamp' ] = $date -> getTimestamp ();
}
}
} else {
return $this -> captureObject ( $object , $eventId , $user , $log );
}
// At this point we have an existingObject that we can edit
$recoverFields = array (
'name' ,
'meta-category' ,
'description' ,
'template_uuid' ,
'template_version' ,
'distribution' ,
'sharing_group_id' ,
'comment' ,
'deleted'
);
foreach ( $recoverFields as $rF ) {
if ( ! isset ( $object [ $rF ])) {
$object [ $rF ] = $existingObject [ 'Object' ][ $rF ];
}
}
$object [ 'id' ] = $existingObject [ 'Object' ][ 'id' ];
$object [ 'uuid' ] = $existingObject [ 'Object' ][ 'uuid' ];
$object [ 'event_id' ] = $eventId ;
if ( $object [ 'distribution' ] == 4 ) {
$object [ 'sharing_group_id' ] = $this -> SharingGroup -> captureSG ( $object [ 'SharingGroup' ], $user );
}
if ( ! $this -> save ( $object )) {
$log -> create ();
$log -> save ( array (
'org' => $user [ 'Organisation' ][ 'name' ],
'model' => 'Object' ,
'model_id' => 0 ,
'email' => $user [ 'email' ],
'action' => 'edit' ,
'user_id' => $user [ 'id' ],
'title' => 'Attribute dropped due to validation for Event ' . $eventId . ' failed: ' . $object [ 'name' ],
'change' => 'Validation errors: ' . json_encode ( $this -> validationErrors ) . ' Full Object: ' . json_encode ( $attribute ),
));
return $this -> validationErrors ;
} else {
$this -> Event -> unpublishEvent ( $eventId );
}
if ( ! empty ( $object [ 'Attribute' ])) {
foreach ( $object [ 'Attribute' ] as $attribute ) {
$result = $this -> Attribute -> editAttribute ( $attribute , $eventId , $user , $object [ 'id' ], $log );
}
}
return true ;
}
2017-09-04 17:26:45 +02:00
2018-07-19 11:48:22 +02:00
public function updateTimestamp ( $id )
{
$date = new DateTime ();
$object = $this -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.id' => $id )
));
$object [ 'Object' ][ 'timestamp' ] = $date -> getTimestamp ();
$object [ 'Object' ][ 'skip_zmq' ] = 1 ;
2019-03-05 12:24:56 +01:00
$object [ 'Object' ][ 'skip_kafka' ] = 1 ;
2018-07-19 11:48:22 +02:00
$result = $this -> save ( $object );
return $result ;
}
2017-09-04 23:12:46 +02:00
2018-07-19 11:48:22 +02:00
// Hunt down all LEDA and CASTOR clones
public function removeOrphanedObjects ()
{
$orphans = $this -> find ( 'list' , array (
'fields' => array ( 'Object.id' , 'Object.id' ),
'conditions' => array ( 'Event.id' => null ),
'contain' => array ( 'Event' => array ( 'fields' => array ( 'id' )))
));
foreach ( $orphans as $orphan ) {
$this -> delete ( $orphan );
}
return count ( $orphans );
}
2019-05-08 16:56:19 +02:00
public function validObjectsFromAttributeTypes ( $user , $event_id , $selected )
{
$attributes = $this -> Attribute -> fetchAttributesSimple ( $user ,
array (
'conditions' => array (
'id' => $selected ,
2019-05-17 16:02:06 +02:00
'event_id' => $event_id ,
'object_id' => 0
2019-05-08 16:56:19 +02:00
),
)
);
// $attribute_types = array_keys(Hash::combine($attributes, '{n}.Attribute.type'));
2019-05-17 16:02:06 +02:00
if ( empty ( $attributes )) {
return array ();
}
2019-05-08 16:56:19 +02:00
$attribute_types = array ();
foreach ( $attributes as $i => $attribute ) {
$attribute_types [ $attribute [ 'Attribute' ][ 'type' ]] = 1 ;
$attributes [ $i ][ 'Attribute' ][ 'object_relation' ] = $attribute [ 'Attribute' ][ 'type' ];
}
$attribute_types = array_keys ( $attribute_types );
$db = $this -> getDataSource ();
2019-05-17 16:02:06 +02:00
// # TEST 1
// array_walk($attribute_types, function(&$value) { $value = '"' . $value . '"'; });
// $potential_templates = $db->fetchAll(
// 'SELECT object_templates.id, object_templates.name, count(object_template_elements.type) as type_count FROM object_templates '
// .'RIGHT JOIN object_template_elements ON object_templates.id = object_template_elements.object_template_id '
// .'WHERE object_templates.active=1 AND object_template_elements.type IN (' . implode(',', $attribute_types) . ') '
// .'GROUP BY object_templates.name ORDER BY type_count DESC;'
// );
// $potential_template_ids = Hash::extract($potential_templates, '{n}.object_templates.id');
// TEST 2
// $potential_templates = $this->ObjectTemplate->find('all', array(
// 'recursive' => -1,
// 'fields' => array(
// 'ObjectTemplate.id',
// 'ObjectTemplate.name',
// 'COUNT(ObjectTemplateElement.type) as type_count'
// ),
// 'conditions' => array(
// 'ObjectTemplate.active' => true,
// ),
// 'contain' => array(
// 'ObjectTemplateElement' => array(
// 'fields' => array('ObjectTemplateElement.object_relation', 'ObjectTemplateElement.type'),
// 'conditions' => array('ObjectTemplateElement.type' => $attribute_types)
// )
// ),
// 'group' => 'ObjectTemplate.name',
// 'order' => 'type_count DESC'
// ));
$potential_templates = $this -> ObjectTemplate -> find ( 'all' , array (
'recursive' => - 1 ,
'fields' => array (
'ObjectTemplate.id' ,
'ObjectTemplate.name' ,
'COUNT(ObjectTemplateElement.type) as type_count'
),
'conditions' => array (
'ObjectTemplate.active' => true ,
'ObjectTemplateElement.type' => $attribute_types
),
'joins' => array (
array (
'table' => $db -> fullTableName ( $this -> ObjectTemplate -> ObjectTemplateElement ),
'alias' => 'ObjectTemplateElement' ,
'type' => 'RIGHT' ,
'fields' => array ( 'ObjectTemplateElement.object_relation' , 'ObjectTemplateElement.type' ),
'conditions' => array ( 'ObjectTemplate.id = ObjectTemplateElement.object_template_id' )
)
),
'group' => 'ObjectTemplate.name' ,
'order' => 'type_count DESC'
));
$potential_template_ids = Hash :: extract ( $potential_templates , '{n}.ObjectTemplate.id' );
2019-05-08 16:56:19 +02:00
$templates = $this -> ObjectTemplate -> find ( 'all' , array (
'recursive' => - 1 ,
'conditions' => array ( 'id' => $potential_template_ids ),
'contain' => 'ObjectTemplateElement'
));
foreach ( $templates as $i => $template ) {
2019-05-17 16:02:06 +02:00
$res = $this -> ObjectTemplate -> checkTemplateConformityBasedOnTypes ( $template , $attributes );
$templates [ $i ][ 'ObjectTemplate' ][ 'compatibility' ] = $res [ 'valid' ] ? true : $res [ 'missingTypes' ];
$templates [ $i ][ 'ObjectTemplate' ][ 'invalidTypes' ] = $res [ 'invalidTypes' ];
$templates [ $i ][ 'ObjectTemplate' ][ 'invalidTypesMultiple' ] = $res [ 'invalidTypesMultiple' ];
2019-05-08 16:56:19 +02:00
}
return $templates ;
}
2017-06-13 12:08:26 +02:00
}