2017-06-13 12:08:26 +02:00
< ? php
App :: uses ( 'AppModel' , 'Model' );
2020-06-19 16:21:53 +02:00
App :: uses ( 'TmpFileTool' , 'Tools' );
2017-06-13 12:08:26 +02:00
2020-07-20 10:10:47 +02:00
/**
* @ property Event $Event
2020-07-24 21:53:28 +02:00
* @ property SharingGroup $SharingGroup
2020-09-20 18:46:38 +02:00
* @ property Attribute $Attribute
2020-07-20 10:10:47 +02:00
*/
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
2020-02-29 08:57:32 +01:00
public $validFormats = array (
'json' => array ( 'json' , 'JsonExport' , 'json' )
);
2019-06-13 09:16:34 +02:00
public $shortDist = array ( 0 => 'Organisation' , 1 => 'Community' , 2 => 'Connected' , 3 => 'All' , 4 => ' Sharing Group' , 5 => 'Inherit' );
2018-07-19 11:48:22 +02:00
public $validate = array (
2018-11-23 14:11:33 +01:00
'uuid' => array (
'uuid' => array (
2020-09-01 19:05:06 +02:00
'rule' => 'uuid' ,
2020-09-18 10:55:52 +02:00
'message' => 'Please provide a valid RFC 4122 UUID'
2018-11-23 14:11:33 +01:00
),
'unique' => array (
'rule' => 'isUnique' ,
'message' => 'The UUID provided is not unique' ,
'required' => 'create'
2020-01-27 16:29:28 +01:00
),
),
'first_seen' => array (
'rule' => array ( 'datetimeOrNull' ),
'required' => false ,
'message' => array ( 'Invalid ISO 8601 format' )
),
'last_seen' => array (
'rule' => array ( 'datetimeOrNull' ),
'required' => false ,
'message' => array ( 'Invalid ISO 8601 format' )
2018-11-23 14:11:33 +01:00
)
2018-07-19 11:48:22 +02:00
);
2017-06-13 12:08:26 +02:00
2021-01-20 15:10:16 +01:00
private $__objectDuplicationCheckCache = [];
2020-09-20 18:18:46 +02:00
public function buildFilterConditions ( & $params )
2020-02-29 08:57:32 +01:00
{
2020-09-20 18:18:46 +02:00
$conditions = [];
2020-02-29 08:57:32 +01:00
if ( isset ( $params [ 'wildcard' ])) {
$temp = array ();
$options = array (
'filter' => 'wildcard' ,
'scope' => 'Object' ,
'pop' => false ,
'context' => 'Event'
);
$conditions [ 'AND' ][] = array ( 'OR' => $this -> Event -> set_filter_wildcard_attributes ( $params , $temp , $options ));
} else {
if ( isset ( $params [ 'ignore' ])) {
$params [ 'to_ids' ] = array ( 0 , 1 );
$params [ 'published' ] = array ( 0 , 1 );
}
$simple_params = array (
'Object' => array (
'object_name' => array ( 'function' => 'set_filter_object_name' ),
'object_template_uuid' => array ( 'function' => 'set_filter_object_template_uuid' ),
'object_template_version' => array ( 'function' => 'set_filter_object_template_version' ),
'deleted' => array ( 'function' => 'set_filter_deleted' )
),
'Event' => array (
'eventid' => array ( 'function' => 'set_filter_eventid' ),
'eventinfo' => array ( 'function' => 'set_filter_eventinfo' ),
'ignore' => array ( 'function' => 'set_filter_ignore' ),
'from' => array ( 'function' => 'set_filter_timestamp' ),
'to' => array ( 'function' => 'set_filter_timestamp' ),
'date' => array ( 'function' => 'set_filter_date' ),
'tags' => array ( 'function' => 'set_filter_tags' ),
'last' => array ( 'function' => 'set_filter_timestamp' , 'pop' => true ),
'timestamp' => array ( 'function' => 'set_filter_timestamp' , 'pop' => true ),
'event_timestamp' => array ( 'function' => 'set_filter_timestamp' , 'pop' => true ),
'publish_timestamp' => array ( 'function' => 'set_filter_timestamp' ),
'org' => array ( 'function' => 'set_filter_org' ),
'uuid' => array ( 'function' => 'set_filter_uuid' ),
'published' => array ( 'function' => 'set_filter_published' )
),
'Attribute' => array (
'value' => array ( 'function' => 'set_filter_value' ),
'category' => array ( 'function' => 'set_filter_simple_attribute' ),
'type' => array ( 'function' => 'set_filter_simple_attribute' ),
'object_relation' => array ( 'function' => 'set_filter_simple_attribute' ),
'tags' => array ( 'function' => 'set_filter_tags' , 'pop' => true ),
'uuid' => array ( 'function' => 'set_filter_uuid' ),
'deleted' => array ( 'function' => 'set_filter_deleted' ),
'timestamp' => array ( 'function' => 'set_filter_timestamp' ),
'attribute_timestamp' => array ( 'function' => 'set_filter_timestamp' ),
'first_seen' => array ( 'function' => 'set_filter_seen' ),
'last_seen' => array ( 'function' => 'set_filter_seen' ),
'to_ids' => array ( 'function' => 'set_filter_to_ids' ),
'comment' => array ( 'function' => 'set_filter_comment' )
)
);
foreach ( $params as $param => $paramData ) {
foreach ( $simple_params as $scope => $simple_param_scoped ) {
if ( isset ( $simple_param_scoped [ $param ]) && isset ( $params [ $param ]) && $params [ $param ] !== false ) {
$options = array (
'filter' => $param ,
'scope' => $scope ,
'pop' => ! empty ( $simple_param_scoped [ $param ][ 'pop' ]),
'context' => 'Attribute'
);
2020-06-14 20:23:48 +02:00
if ( $scope === 'Attribute' ) {
$subQueryOptions = array (
'fields' => [ 'Attribute.object_id' ],
'group' => 'Attribute.object_id' ,
'recursive' => - 1 ,
'conditions' => array (
'Attribute.object_id NOT' => 0 ,
$this -> Event -> { $simple_param_scoped [ $param ][ 'function' ]}( $params , $conditions , $options )
)
);
$conditions [ 'AND' ][] = $this -> subQueryGenerator ( $this -> Attribute , $subQueryOptions , 'Object.id' );
} else {
$conditions = $this -> Event -> { $simple_param_scoped [ $param ][ 'function' ]}( $params , $conditions , $options );
}
2020-02-29 08:57:32 +01:00
}
}
}
}
return $conditions ;
}
2020-01-27 16:29:28 +01:00
// check whether the variable is null or datetime
public function datetimeOrNull ( $fields )
{
$k = array_keys ( $fields )[ 0 ];
$seen = $fields [ $k ];
try {
new DateTime ( $seen );
$returnValue = true ;
} catch ( Exception $e ) {
$returnValue = false ;
}
return $returnValue || is_null ( $seen );
}
2019-06-13 09:16:34 +02:00
public function afterFind ( $results , $primary = false )
{
foreach ( $results as $k => $v ) {
2019-12-16 10:47:07 +01:00
$results [ $k ] = $this -> Attribute -> UTCToISODatetime ( $results [ $k ], $this -> alias );
2019-06-13 09:16:34 +02:00
}
return $results ;
}
public function beforeSave ( $options = array ()) {
2019-12-16 10:47:07 +01:00
$this -> data = $this -> Attribute -> ISODatetimeToUTC ( $this -> data , $this -> alias );
2019-06-13 09:16:34 +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 ();
}
2019-06-13 09:16:34 +02:00
// parse first_seen different formats
if ( isset ( $this -> data [ $this -> alias ][ 'first_seen' ])) {
$this -> data [ $this -> alias ][ 'first_seen' ] = $this -> data [ $this -> alias ][ 'first_seen' ] === '' ? null : $this -> data [ $this -> alias ][ 'first_seen' ];
}
// parse last_seen different formats
if ( isset ( $this -> data [ $this -> alias ][ 'last_seen' ])) {
$this -> data [ $this -> alias ][ 'last_seen' ] = $this -> data [ $this -> alias ][ 'last_seen' ] === '' ? null : $this -> data [ $this -> alias ][ 'last_seen' ];
}
2018-07-19 11:48:22 +02:00
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
2020-02-10 14:30:34 +01:00
public function checkForDuplicateObjects ( $object , $eventId )
2018-07-19 11:48:22 +02:00
{
2020-02-10 14:30:34 +01:00
$newObjectAttributes = array ();
$existingObjectAttributes = array ();
2021-01-20 15:10:16 +01:00
if ( isset ( $object [ 'Object' ][ 'Attribute' ])) {
$attributeArray = $object [ 'Object' ][ 'Attribute' ];
} else {
$attributeArray = $object [ 'Attribute' ];
}
foreach ( $attributeArray as $attribute ) {
2021-01-12 15:02:20 +01:00
if ( $attribute [ 'type' ] === 'malware-sample' ) {
if ( strpos ( $attribute [ 'value' ], '|' ) === false && ! empty ( $attribute [ 'data' ])) {
$attribute [ 'value' ] = $attribute [ 'value' ] . '|' . md5 ( base64_decode ( $attribute [ 'data' ]));
}
}
2020-02-10 14:39:58 +01:00
$newObjectAttributes [] = hash (
'sha256' ,
2021-01-12 15:02:20 +01:00
$attribute [ 'object_relation' ] . $attribute [ 'category' ] . $attribute [ 'type' ] . $this -> data [ 'Attribute' ][ 'value' ] = $this -> Attribute -> modifyBeforeValidation ( $attribute [ 'type' ], $attribute [ 'value' ])
2020-02-10 14:39:58 +01:00
);
2020-02-10 14:30:34 +01:00
}
$newObjectAttributeCount = count ( $newObjectAttributes );
2021-01-20 15:10:16 +01:00
if ( ! isset ( $this -> __objectDuplicationCheckCache [ $object [ 'Object' ][ 'template_uuid' ]])) {
$this -> __objectDuplicationCheckCache [ $object [ 'Object' ][ 'template_uuid' ]] = $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 , 'event_id' => $eventId )
));
}
2020-02-10 14:30:34 +01:00
$oldObjects = array ();
2021-01-20 15:10:16 +01:00
foreach ( $this -> __objectDuplicationCheckCache [ $object [ 'Object' ][ 'template_uuid' ]] as $k => $existingObject ) {
2020-02-10 14:39:58 +01:00
$temp = array ();
2020-02-10 14:30:34 +01:00
if ( ! empty ( $existingObject [ 'Attribute' ]) && $newObjectAttributeCount == count ( $existingObject [ 'Attribute' ])) {
foreach ( $existingObject [ 'Attribute' ] as $existingAttribute ) {
2020-02-10 14:39:58 +01:00
$temp [] = hash (
'sha256' ,
2021-01-12 13:06:52 +01:00
$existingAttribute [ 'object_relation' ] . $existingAttribute [ 'category' ] . $existingAttribute [ 'type' ] . $existingAttribute [ 'value' ]
2020-02-10 14:39:58 +01:00
);
}
if ( empty ( array_diff ( $temp , $newObjectAttributes ))) {
return true ;
2020-02-10 14:30:34 +01:00
}
}
}
return false ;
}
public function saveObject ( $object , $eventId , $template = false , $user , $errorBehaviour = 'drop' , $breakOnDuplicate = false )
{
if ( $breakOnDuplicate ) {
$duplicate = $this -> checkForDuplicateObjects ( $object , $eventId );
2020-02-10 14:39:58 +01:00
if ( $duplicate ) {
return array ( 'value' => array ( 'Duplicate object found. Since breakOnDuplicate is set the object will not be added.' ));
}
2020-02-10 14:30:34 +01:00
}
2018-07-19 11:48:22 +02:00
$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 ])) {
2020-11-17 11:37:40 +01:00
return array ( 'template' => array ( __ ( 'No valid template found and object lacking template information. (%s)' , $k )));
2018-07-19 11:48:22 +02:00
}
}
}
$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 ;
2019-07-04 14:05:47 +02:00
if (
( ! array_key_exists ( 'first_seen' , $object [ 'Attribute' ][ $k ]) || is_null ( $object [ 'Attribute' ][ $k ][ 'first_seen' ])) &&
2019-07-05 10:40:00 +02:00
( array_key_exists ( 'first_seen' , $object [ 'Object' ]) && ! is_null ( $object [ 'Object' ][ 'first_seen' ]))
2019-07-04 14:05:47 +02:00
) {
$object [ 'Attribute' ][ $k ][ 'first_seen' ] = $object [ 'Object' ][ 'first_seen' ];
2019-07-04 13:52:29 +02:00
}
2019-07-04 14:05:47 +02:00
if (
( ! array_key_exists ( 'last_seen' , $object [ 'Attribute' ][ $k ]) || is_null ( $object [ 'Attribute' ][ $k ][ 'last_seen' ])) &&
2019-07-05 10:40:00 +02:00
( array_key_exists ( 'last_seen' , $object [ 'Object' ]) && ! is_null ( $object [ 'Object' ][ 'last_seen' ]))
2019-07-04 14:05:47 +02:00
) {
$object [ 'Attribute' ][ $k ][ 'last_seen' ] = $object [ 'Object' ][ 'last_seen' ];
2019-07-04 13:52:29 +02:00
}
2018-07-19 11:48:22 +02:00
}
2020-07-24 14:30:41 +02:00
$this -> Attribute -> saveAttributes ( $object [ 'Attribute' ], $user );
2018-07-19 11:48:22 +02:00
} else {
$result = $this -> validationErrors ;
}
return $result ;
}
2017-09-17 12:26:06 +02:00
2020-09-20 18:15:30 +02:00
public function buildConditions ( array $user )
2018-07-19 11:48:22 +02:00
{
2020-09-21 11:33:19 +02:00
if ( $user [ 'Role' ][ 'perm_site_admin' ]) {
return [];
2018-07-19 11:48:22 +02:00
}
2020-09-21 11:33:19 +02:00
$sgids = $this -> Event -> cacheSgids ( $user , true );
return [
'AND' => [
'OR' => [
'Event.org_id' => $user [ 'org_id' ], // if event is owned by current user org, allow access to all objects
'AND' => [
$this -> Event -> createEventConditions ( $user ),
'OR' => [
'Object.distribution' => array ( 1 , 2 , 3 , 5 ),
'AND' => [
'Object.distribution' => 4 ,
'Object.sharing_group_id' => $sgids ,
]
]
]
]
]
];
2018-07-19 11:48:22 +02:00
}
2017-06-13 12:08:26 +02:00
2019-06-13 09:16:34 +02:00
public function fetchObjectSimple ( $user , $options = array ())
2020-09-20 18:16:11 +02:00
{
$params = array (
'conditions' => $this -> buildConditions ( $user ),
'fields' => array (),
'recursive' => - 1
);
if ( isset ( $options [ 'conditions' ])) {
$params [ 'conditions' ][ 'AND' ][] = $options [ 'conditions' ];
}
if ( isset ( $options [ 'fields' ])) {
$params [ 'fields' ] = $options [ 'fields' ];
2019-06-13 09:16:34 +02:00
}
2020-09-20 18:16:11 +02:00
$results = $this -> find ( 'all' , array (
'conditions' => $params [ 'conditions' ],
'recursive' => - 1 ,
'fields' => $params [ 'fields' ],
'contain' => array ( 'Event' => array ( 'distribution' , 'id' , 'user_id' , 'orgc_id' , 'org_id' )),
'sort' => false
));
return $results ;
}
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 ())
{
$attributeConditions = array ();
if ( ! $user [ 'Role' ][ 'perm_site_admin' ]) {
2020-09-20 18:43:07 +02:00
$sgids = $this -> Event -> cacheSgids ( $user , true );
2018-07-19 11:48:22 +02:00
$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 ,
2020-09-20 18:43:07 +02:00
'Attribute.sharing_group_id' => $sgids ,
2018-07-19 11:48:22 +02:00
)
)
)
)
);
}
$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'
)
)
2020-02-29 08:57:32 +01:00
),
2018-07-19 11:48:22 +02:00
);
2020-05-06 09:32:44 +02:00
if ( ! empty ( $options [ 'metadata' ])) {
unset ( $params [ 'contain' ][ 'Attribute' ]);
}
if ( empty ( $options [ 'metadata' ]) && empty ( $options [ 'includeAllTags' ])) {
2018-07-19 11:48:22 +02:00
$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' );
}
2020-05-06 09:32:44 +02:00
if (
empty ( $options [ 'metadata' ]) &&
Configure :: read ( 'MISP.proposals_block_attributes' ) &&
isset ( $options [ 'conditions' ][ 'AND' ][ 'Attribute.to_ids' ]) &&
$options [ 'conditions' ][ 'AND' ][ 'Attribute.to_ids' ] == 1
) {
2018-07-19 11:48:22 +02:00
$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 [ '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 ;
}
2020-05-06 09:32:44 +02:00
if ( empty ( $options [ 'metadata' ]) && ( ! $user [ 'Role' ][ 'perm_sync' ] || ! isset ( $options [ 'deleted' ]) || ! $options [ 'deleted' ])) {
2018-07-19 11:48:22 +02:00
$params [ 'contain' ][ 'Attribute' ][ 'conditions' ][ 'AND' ][ 'Attribute.deleted' ] = 0 ;
}
if ( isset ( $options [ 'group' ])) {
$params [ 'group' ] = array_merge ( array ( 'Object.id' ), $options [ 'group' ]);
}
2020-02-29 08:57:32 +01:00
if ( isset ( $options [ 'limit' ])) {
$params [ 'limit' ] = $options [ 'limit' ];
if ( isset ( $options [ 'page' ])) {
$params [ 'page' ] = $options [ 'page' ];
}
}
2018-07-19 11:48:22 +02:00
$results = $this -> find ( 'all' , $params );
2020-09-03 15:24:03 +02:00
if ( $options [ 'enforceWarninglist' ] && ! isset ( $this -> Warninglist )) {
2018-07-19 11:48:22 +02:00
$this -> Warninglist = ClassRegistry :: init ( 'Warninglist' );
}
$results = array_values ( $results );
$proposals_block_attributes = Configure :: read ( 'MISP.proposals_block_attributes' );
2020-05-06 09:32:44 +02:00
if ( empty ( $options [ 'metadata' ])) {
2020-09-20 18:46:38 +02:00
foreach ( $results as $key => $object ) {
foreach ( $object [ 'Attribute' ] as $key2 => $attribute ) {
2020-09-07 16:37:38 +02:00
if ( $options [ 'enforceWarninglist' ] && ! $this -> Warninglist -> filterWarninglistAttribute ( $attribute [ 'Attribute' ])) {
2018-07-19 11:48:22 +02:00
unset ( $results [ $key ][ $key2 ]);
2020-05-06 09:32:44 +02:00
continue ;
2018-07-19 11:48:22 +02:00
}
2020-05-06 09:32:44 +02:00
if ( $proposals_block_attributes ) {
if ( ! empty ( $attribute [ 'ShadowAttribute' ])) {
unset ( $results [ $key ][ $key2 ]);
} else {
unset ( $results [ $key ][ $key2 ][ 'ShadowAttribute' ]);
}
}
if ( $options [ 'withAttachments' ]) {
2020-09-20 18:46:38 +02:00
if ( $this -> Attribute -> typeIsAttachment ( $attribute [ 'type' ])) {
$encodedFile = $this -> Attribute -> base64EncodeAttachment ( $attribute );
$results [ $key ][ 'Attribute' ][ $key2 ][ 'data' ] = $encodedFile ;
2020-05-06 09:32:44 +02:00
}
2018-07-19 11:48:22 +02:00
}
}
}
}
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 ;
2019-08-22 15:28:25 +02:00
unset ( $v [ 'uuid' ]); // force creating a new attribute if template element entry gets reused
2018-07-19 11:48:22 +02:00
} 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
2020-10-29 09:02:50 +01:00
/**
2018-07-19 11:48:22 +02:00
* Clean the attribute list up from artifacts introduced by the object form
2020-10-29 09:02:50 +01:00
* @ param array $attributes
* @ return string | array
2018-07-19 11:48:22 +02:00
*/
public function attributeCleanup ( $attributes )
{
if ( empty ( $attributes [ 'Attribute' ])) {
2019-08-05 10:50:39 +02:00
return $attributes ;
2018-07-19 11:48:22 +02:00
}
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 ();
}
2019-12-16 15:00:30 +01:00
if ( ! isset ( $attributes [ 'Attribute' ][ $k ][ 'first_seen' ])) {
$attributes [ 'Attribute' ][ $k ][ 'first_seen' ] = null ;
}
if ( ! isset ( $attributes [ 'Attribute' ][ $k ][ 'last_seen' ])) {
$attributes [ 'Attribute' ][ $k ][ 'last_seen' ] = null ;
}
2018-07-19 11:48:22 +02:00
unset ( $attributes [ 'Attribute' ][ $k ][ 'save' ]);
}
return $attributes ;
}
2017-07-02 20:32:30 +02:00
2019-10-28 15:45:33 +01:00
// Set Object's *-seen (and ObjectAttribute's *-seen and ObjectAttribute's value if requested) to the provided *-seen value
// Therefore, synchronizing the 3 values
public function syncObjectAndAttributeSeen ( $object , $forcedSeenOnElements , $applyOnAttribute = True ) {
if ( empty ( $forcedSeenOnElements )) {
return $object ;
}
if ( isset ( $forcedSeenOnElements [ 'first_seen' ])) {
$object [ 'Object' ][ 'first_seen' ] = $forcedSeenOnElements [ 'first_seen' ];
}
if ( isset ( $forcedSeenOnElements [ 'last_seen' ])) {
$object [ 'Object' ][ 'last_seen' ] = $forcedSeenOnElements [ 'last_seen' ];
}
if ( $applyOnAttribute ) {
if ( isset ( $object [ 'Attribute' ])) {
$attributes = $object [ 'Attribute' ];
} else {
$attributes = $this -> find ( 'first' , array (
'conditions' => array ( 'id' => $object [ 'Object' ][ 'id' ]),
'contain' => array ( 'Attribute' )
))[ 'Attribute' ];
}
foreach ( $attributes as $i => $attribute ) {
if ( isset ( $forcedSeenOnElements [ 'first_seen' ])) {
$attributes [ $i ][ 'first_seen' ] = $forcedSeenOnElements [ 'first_seen' ];
if ( $attribute [ 'object_relation' ] == 'first-seen' ) {
$attributes [ $i ][ 'value' ] = $forcedSeenOnElements [ 'first_seen' ];
2019-06-13 09:16:34 +02:00
}
2019-10-28 15:45:33 +01:00
} elseif ( isset ( $forcedSeenOnElements [ 'last_seen' ])) {
$attributes [ $i ][ 'last_seen' ] = $forcedSeenOnElements [ 'last_seen' ];
if ( $attribute [ 'object_relation' ] == 'last-seen' ) {
$attributes [ $i ][ 'value' ] = $forcedSeenOnElements [ 'last_seen' ];
2019-06-13 09:16:34 +02:00
}
}
}
2019-10-28 15:45:33 +01:00
$object [ 'Attribute' ] = $attributes ;
2019-06-13 09:16:34 +02:00
}
2019-10-28 15:45:33 +01:00
return $object ;
2019-06-13 09:16:34 +02:00
}
2020-07-24 14:30:41 +02:00
public function deltaMerge ( $object , $objectToSave , $onlyAddNewAttribute = false , $user )
2018-07-19 11:48:22 +02:00
{
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 );
}
2019-06-13 09:16:34 +02:00
if ( isset ( $objectToSave [ 'Object' ][ 'comment' ])) {
$object [ 'Object' ][ 'comment' ] = $objectToSave [ 'Object' ][ 'comment' ];
}
2020-07-29 15:46:20 +02:00
if ( isset ( $objectToSave [ 'Object' ][ 'template_version' ])) {
$object [ 'Object' ][ 'template_version' ] = $objectToSave [ 'Object' ][ 'template_version' ];
}
2019-06-13 09:16:34 +02:00
if ( isset ( $objectToSave [ 'Object' ][ 'distribution' ])) {
$object [ 'Object' ][ 'distribution' ] = $objectToSave [ 'Object' ][ 'distribution' ];
if ( $object [ 'Object' ][ 'distribution' ] == 4 ) {
$object [ 'Object' ][ 'sharing_group_id' ] = $objectToSave [ 'Object' ][ 'sharing_group_id' ];
}
2018-07-19 11:48:22 +02:00
}
$date = new DateTime ();
$object [ 'Object' ][ 'timestamp' ] = $date -> getTimestamp ();
2019-10-28 15:45:33 +01:00
$forcedSeenOnElements = array ();
2019-06-13 09:16:34 +02:00
if ( isset ( $objectToSave [ 'Object' ][ 'first_seen' ])) {
2019-10-28 15:45:33 +01:00
$forcedSeenOnElements [ 'first_seen' ] = $objectToSave [ 'Object' ][ 'first_seen' ];
2019-06-13 09:16:34 +02:00
}
if ( isset ( $objectToSave [ 'Object' ][ 'last_seen' ])) {
2019-10-28 15:45:33 +01:00
$forcedSeenOnElements [ 'last_seen' ] = $objectToSave [ 'Object' ][ 'last_seen' ];
2019-06-13 09:16:34 +02:00
}
2019-10-28 15:45:33 +01:00
$object = $this -> syncObjectAndAttributeSeen ( $object , $forcedSeenOnElements , false );
2020-01-27 16:29:28 +01:00
$saveResult = $this -> save ( $object );
if ( $saveResult === false ) {
return $this -> validationErrors ;
}
2019-06-13 09:16:34 +02:00
if ( ! $onlyAddNewAttribute ) {
2019-10-28 15:45:33 +01:00
$checkFields = array ( 'category' , 'value' , 'to_ids' , 'distribution' , 'sharing_group_id' , 'comment' , 'disable_correlation' , 'first_seen' , 'last_seen' );
2019-10-02 11:23:04 +02:00
if ( ! empty ( $objectToSave [ 'Attribute' ])) {
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 ;
}
2020-11-11 09:56:05 +01:00
if ( isset ( $newAttribute [ $f ]) && $this -> attributeValueDifferent ( $originalAttribute [ $f ], $newAttribute [ $f ], $f )) {
2019-10-02 11:23:04 +02:00
$different = true ;
}
2019-08-05 10:50:39 +02:00
}
2019-10-02 11:23:04 +02:00
if ( $different ) {
$newAttribute [ 'id' ] = $originalAttribute [ 'id' ];
$newAttribute [ 'event_id' ] = $object [ 'Object' ][ 'event_id' ];
$newAttribute [ 'object_id' ] = $object [ 'Object' ][ 'id' ];
$newAttribute [ 'timestamp' ] = $date -> getTimestamp ();
2020-07-24 16:19:02 +02:00
$result = $this -> Event -> Attribute -> save ( array ( 'Attribute' => $newAttribute ), array ( 'fieldList' => $this -> Attribute -> editableFields ));
2020-07-24 13:55:34 +02:00
if ( $result ) {
2020-07-24 14:30:41 +02:00
$this -> Event -> Attribute -> AttributeTag -> handleAttributeTags ( $user , $newAttribute , $newAttribute [ 'event_id' ], $capture = true );
2020-07-24 13:55:34 +02:00
}
2019-08-05 10:50:39 +02:00
}
2019-10-02 11:23:04 +02:00
unset ( $object [ 'Attribute' ][ $origKey ]);
continue 2 ;
2018-07-19 11:48:22 +02:00
}
}
}
2019-10-02 11:23:04 +02:00
$this -> Event -> Attribute -> create ();
$newAttribute [ 'event_id' ] = $object [ 'Object' ][ 'event_id' ];
$newAttribute [ 'object_id' ] = $object [ 'Object' ][ 'id' ];
// Set seen of object at attribute level
2019-10-28 15:45:33 +01:00
if ( isset ( $forcedSeenOnElements [ 'first_seen' ])) {
2020-11-06 09:05:57 +01:00
$newAttribute [ 'first_seen' ] = empty ( $newAttribute [ 'first_seen' ]) ? $forcedSeenOnElements [ 'first_seen' ] : $newAttribute [ 'first_seen' ];
2019-10-28 15:45:33 +01:00
if ( $newAttribute [ 'object_relation' ] == 'first-seen' ) {
$newAttribute [ 'value' ] = $forcedSeenOnElements [ 'first_seen' ];
}
2019-08-05 10:50:39 +02:00
}
2019-10-28 15:45:33 +01:00
if ( isset ( $forcedSeenOnElements [ 'last_seen' ])) {
2020-11-06 09:05:57 +01:00
$newAttribute [ 'last_seen' ] = empty ( $newAttribute [ 'last_seen' ]) ? $forcedSeenOnElements [ 'last_seen' ] : $newAttribute [ 'last_seen' ];
2019-10-28 15:45:33 +01:00
if ( $newAttribute [ 'object_relation' ] == 'last-seen' ) {
$newAttribute [ 'value' ] = $forcedSeenOnElements [ 'last_seen' ];
}
2019-10-02 11:23:04 +02:00
}
2020-07-24 10:13:54 +02:00
if ( ! isset ( $newAttribute [ 'distribution' ])) {
2019-10-02 11:23:04 +02:00
$newAttribute [ 'distribution' ] = Configure :: read ( 'MISP.default_attribute_distribution' );
if ( $newAttribute [ 'distribution' ] == 'event' ) {
$newAttribute [ 'distribution' ] = 5 ;
}
2019-06-13 09:16:34 +02:00
}
2020-07-24 13:55:34 +02:00
$saveResult = $this -> Event -> Attribute -> save ( $newAttribute );
if ( $saveResult ) {
$newAttribute [ 'id' ] = $this -> Event -> Attribute -> id ;
2020-07-24 14:30:41 +02:00
$this -> Event -> Attribute -> AttributeTag -> handleAttributeTags ( $user , $newAttribute , $newAttribute [ 'event_id' ], $capture = true );
2020-07-24 13:55:34 +02:00
}
2019-10-02 11:23:04 +02:00
$attributeArrays [ 'add' ][] = $newAttribute ;
unset ( $objectToSave [ 'Attribute' ][ $newKey ]);
}
foreach ( $object [ 'Attribute' ] as $origKey => $originalAttribute ) {
$originalAttribute [ 'deleted' ] = 1 ;
2020-07-24 16:19:02 +02:00
$this -> Event -> Attribute -> save ( $originalAttribute , array ( 'fieldList' => $this -> Attribute -> editableFields ));
2019-02-10 13:08:12 +01:00
}
2019-08-05 10:50:39 +02:00
}
2019-06-13 09:16:34 +02:00
} else { // we only add the new attribute
$newAttribute = $objectToSave [ 'Attribute' ][ 0 ];
2019-10-28 15:45:33 +01:00
$this -> Event -> Attribute -> create ();
$newAttribute [ 'event_id' ] = $object [ 'Object' ][ 'event_id' ];
$newAttribute [ 'object_id' ] = $object [ 'Object' ][ 'id' ];
// Set seen of object at attribute level
if (
( ! array_key_exists ( 'first_seen' , $newAttribute ) || is_null ( $newAttribute [ 'first_seen' ])) &&
( ! array_key_exists ( 'first_seen' , $object [ 'Object' ]) && ! is_null ( $object [ 'Object' ][ 'first_seen' ]))
) {
$newAttribute [ 'first_seen' ] = $object [ 'Object' ][ 'first_seen' ];
}
if (
( ! array_key_exists ( 'last_seen' , $newAttribute ) || is_null ( $newAttribute [ 'last_seen' ])) &&
( ! array_key_exists ( 'last_seen' , $object [ 'Object' ]) && ! is_null ( $object [ 'Object' ][ 'last_seen' ]))
) {
$newAttribute [ 'last_seen' ] = $object [ 'Object' ][ 'last_seen' ];
$different = true ;
}
2020-07-24 10:13:54 +02:00
if ( ! isset ( $newAttribute [ 'distribution' ])) {
2019-10-28 15:45:33 +01:00
$newAttribute [ 'distribution' ] = Configure :: read ( 'MISP.default_attribute_distribution' );
if ( $newAttribute [ 'distribution' ] == 'event' ) {
$newAttribute [ 'distribution' ] = 5 ;
2019-02-10 13:08:12 +01:00
}
}
2020-07-24 14:30:41 +02:00
$saveAttributeResult = $this -> Attribute -> saveAttributes ( array ( $newAttribute ), $user );
2019-10-28 15:45:33 +01:00
return $saveAttributeResult ? $this -> id : $this -> validationErrors ;
2018-07-19 11:48:22 +02:00
}
return $this -> id ;
}
2017-07-06 15:04:01 +02:00
2020-07-06 09:17:44 +02:00
public function captureObject ( $object , $eventId , $user , $log = false , $unpublish = true )
2018-07-19 11:48:22 +02:00
{
$this -> create ();
if ( ! isset ( $object [ 'Object' ])) {
$object = array ( 'Object' => $object );
}
2021-01-20 15:10:16 +01:00
if ( ! empty ( $object [ 'Object' ][ 'breakOnDuplicate' ])) {
$duplicate = $this -> checkForDuplicateObjects ( $object , $eventId );
if ( $duplicate ) {
$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 it being a duplicate and breakOnDuplicate being requested for Event ' . $eventId ,
'change' => 'Duplicate object found.' ,
));
}
return true ;
}
2018-07-19 11:48:22 +02:00
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 )) {
2020-07-06 09:17:44 +02:00
if ( $unpublish ) {
$this -> Event -> unpublishEvent ( $eventId );
}
2018-07-19 11:48:22 +02:00
$objectId = $this -> id ;
$partialFails = array ();
2019-12-02 08:47:07 +01:00
if ( ! empty ( $object [ 'Object' ][ 'Attribute' ])) {
foreach ( $object [ 'Object' ][ 'Attribute' ] as $attribute ) {
$this -> Attribute -> captureAttribute ( $attribute , $eventId , $user , $objectId , $log );
}
2018-07-19 11:48:22 +02:00
}
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' ],
2019-07-18 15:40:20 +02:00
'change' => 'Validation errors: ' . json_encode ( $this -> validationErrors ) . ' Full Object: ' . json_encode ( $object ),
2018-07-19 11:48:22 +02:00
));
}
return 'fail' ;
}
2017-08-28 09:18:40 +02:00
2020-07-22 13:10:52 +02:00
public function editObject ( $object , $eventId , $user , $log , $force = false , & $nothingToChange = false )
2018-07-19 11:48:22 +02:00
{
$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' ])) {
2020-05-14 09:34:49 +02:00
if ( $force || $existingObject [ 'Object' ][ 'timestamp' ] >= $object [ 'timestamp' ]) {
2020-07-22 13:10:52 +02:00
$nothingToChange = true ;
2018-07-19 11:48:22 +02:00
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 ;
}
if ( ! empty ( $object [ 'Attribute' ])) {
foreach ( $object [ 'Attribute' ] as $attribute ) {
2020-05-14 09:34:49 +02:00
$result = $this -> Attribute -> editAttribute ( $attribute , $eventId , $user , $object [ 'id' ], $log , $force );
2018-07-19 11:48:22 +02:00
}
}
return true ;
}
2017-09-04 17:26:45 +02:00
2020-08-05 10:12:53 +02:00
public function deleteObject ( array $object , $hard = false , $unpublish = true )
2020-07-23 11:52:46 +02:00
{
$id = $object [ 'Object' ][ 'id' ];
if ( $hard ) {
// For a hard delete, simply run the delete, it will cascade
$this -> delete ( $id );
} else {
// For soft deletes, sanitise the object first if the setting is enabled
if ( Configure :: read ( 'Security.sanitise_attribute_on_delete' )) {
$object [ 'Object' ][ 'name' ] = 'N/A' ;
$object [ 'Object' ][ 'category' ] = 'N/A' ;
$object [ 'Object' ][ 'description' ] = 'N/A' ;
$object [ 'Object' ][ 'template_uuid' ] = 'N/A' ;
$object [ 'Object' ][ 'template_version' ] = 0 ;
$object [ 'Object' ][ 'comment' ] = '' ;
}
$date = new DateTime ();
$object [ 'Object' ][ 'deleted' ] = 1 ;
$object [ 'Object' ][ 'timestamp' ] = $date -> getTimestamp ();
$saveResult = $this -> save ( $object );
if ( ! $saveResult ) {
return $saveResult ;
}
foreach ( $object [ 'Attribute' ] as $attribute ) {
if ( Configure :: read ( 'Security.sanitise_attribute_on_delete' )) {
$attribute [ 'category' ] = 'Other' ;
$attribute [ 'type' ] = 'comment' ;
$attribute [ 'value' ] = 'deleted' ;
$attribute [ 'comment' ] = '' ;
$attribute [ 'to_ids' ] = 0 ;
}
$attribute [ 'deleted' ] = 1 ;
$attribute [ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> save ( array ( 'Attribute' => $attribute ));
$this -> Event -> ShadowAttribute -> deleteAll (
array ( 'ShadowAttribute.old_id' => $attribute [ 'id' ]),
false
);
}
if ( $unpublish ) {
$this -> Event -> unpublishEvent ( $object [ 'Event' ][ 'id' ]);
}
$object_refs = $this -> ObjectReference -> find ( 'all' , array (
'conditions' => array (
'ObjectReference.referenced_type' => 1 ,
'ObjectReference.referenced_id' => $id ,
),
'recursive' => - 1
));
foreach ( $object_refs as $ref ) {
$ref [ 'ObjectReference' ][ 'deleted' ] = 1 ;
$this -> ObjectReference -> save ( $ref );
}
}
return true ;
}
2020-01-16 11:02:56 +01:00
public function updateTimestamp ( $id , $timestamp = false )
2018-07-19 11:48:22 +02:00
{
$date = new DateTime ();
$object = $this -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.id' => $id )
));
2020-01-16 11:02:56 +01:00
$object [ 'Object' ][ 'timestamp' ] = $timestamp == false ? $date -> getTimestamp () : $timestamp ;
2018-07-19 11:48:22 +02:00
$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
2019-05-17 16:28:58 +02:00
public function validObjectsFromAttributeTypes ( $user , $event_id , $selected_attribute_ids )
2019-05-08 16:56:19 +02:00
{
2019-06-12 11:17:17 +02:00
$attributes = $this -> Attribute -> fetchAttributes ( $user ,
2019-05-08 16:56:19 +02:00
array (
'conditions' => array (
2019-06-12 11:17:17 +02:00
'Attribute.id' => $selected_attribute_ids ,
'Attribute.event_id' => $event_id ,
'Attribute.object_id' => 0
2019-05-08 16:56:19 +02:00
),
)
);
2019-05-17 16:02:06 +02:00
if ( empty ( $attributes )) {
2019-05-21 08:35:19 +02:00
return array ( 'templates' => array (), 'types' => array ());
2019-05-17 16:02:06 +02:00
}
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 );
2019-05-17 16:02:06 +02:00
2019-06-18 15:50:48 +02:00
$potential_templates = $this -> ObjectTemplate -> find ( 'list' , array (
2019-05-17 16:02:06 +02:00
'recursive' => - 1 ,
'fields' => array (
'ObjectTemplate.id' ,
'COUNT(ObjectTemplateElement.type) as type_count'
),
'conditions' => array (
'ObjectTemplate.active' => true ,
'ObjectTemplateElement.type' => $attribute_types
),
'joins' => array (
array (
2019-06-12 12:05:13 +02:00
'table' => 'object_template_elements' ,
2019-05-17 16:02:06 +02:00
'alias' => 'ObjectTemplateElement' ,
'type' => 'RIGHT' ,
'fields' => array ( 'ObjectTemplateElement.object_relation' , 'ObjectTemplateElement.type' ),
'conditions' => array ( 'ObjectTemplate.id = ObjectTemplateElement.object_template_id' )
)
),
2019-06-18 15:50:48 +02:00
'group' => 'ObjectTemplate.id' ,
2019-05-17 16:02:06 +02:00
'order' => 'type_count DESC'
));
2019-06-18 15:50:48 +02:00
$potential_template_ids = array_keys ( $potential_templates );
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
}
2019-05-20 14:30:20 +02:00
return array ( 'templates' => $templates , 'types' => $attribute_types );
2019-05-08 16:56:19 +02:00
}
2019-06-06 15:11:34 +02:00
2019-06-12 11:00:17 +02:00
public function groupAttributesIntoObject ( $user , $event_id , $object , $template , $selected_attribute_ids , $selected_object_relation_mapping , $hard_delete_attribute )
2019-06-06 15:11:34 +02:00
{
$saved_object_id = $this -> saveObject ( $object , $event_id , $template , $user );
if ( ! is_numeric ( $saved_object_id )) {
return $saved_object_id ;
}
$saved_object = $this -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.id' => $saved_object_id )
));
$existing_attributes = $this -> Attribute -> fetchAttributes ( $user , array ( 'conditions' => array (
'Attribute.id' => $selected_attribute_ids ,
'Attribute.event_id' => $event_id ,
'Attribute.object_id' => 0
)));
if ( empty ( $existing_attributes )) {
return __ ( 'Selected Attributes do not exist.' );
}
$event = array ( 'Event' => $existing_attributes [ 0 ][ 'Event' ]);
2019-06-12 11:38:19 +02:00
// Duplicate the attribute and its context, otherwise connected instances will drop the duplicated UUID
2019-06-06 15:11:34 +02:00
foreach ( $existing_attributes as $i => $existing_attribute ) {
if ( isset ( $selected_object_relation_mapping [ $existing_attribute [ 'Attribute' ][ 'id' ]])) {
$sightings = $this -> Event -> Sighting -> attachToEvent ( $event , $user , $existing_attribute [ 'Attribute' ][ 'id' ]);
$object_relation = $selected_object_relation_mapping [ $existing_attribute [ 'Attribute' ][ 'id' ]];
$created_attribute = $existing_attribute [ 'Attribute' ];
unset ( $created_attribute [ 'timestamp' ]);
unset ( $created_attribute [ 'id' ]);
unset ( $created_attribute [ 'uuid' ]);
$created_attribute [ 'object_relation' ] = $object_relation ;
$created_attribute [ 'object_id' ] = $saved_object [ 'Object' ][ 'id' ];
if ( isset ( $existing_attribute [ 'AttributeTag' ])) {
$created_attribute [ 'AttributeTag' ] = $existing_attribute [ 'AttributeTag' ];
}
if ( ! empty ( $sightings )) {
$created_attribute [ 'Sighting' ] = $sightings ;
}
$saved_object [ 'Attribute' ][ $i ] = $created_attribute ;
$this -> Attribute -> captureAttribute ( $created_attribute , $event_id , $user , $saved_object [ 'Object' ][ 'id' ]);
2019-06-12 11:56:42 +02:00
$this -> Attribute -> deleteAttribute ( $existing_attribute [ 'Attribute' ][ 'id' ], $user , $hard_delete_attribute );
2019-06-06 15:11:34 +02:00
}
}
return $saved_object [ 'Object' ][ 'id' ];
}
2020-01-17 10:11:51 +01:00
public function resolveUpdatedTemplate ( $template , $object , $update_template_available = false )
{
$toReturn = array (
'updateable_attribute' => false ,
'not_updateable_attribute' => false ,
'newer_template_version' => false ,
'template' => $template
);
if ( ! empty ( $template )) {
$newer_template = $this -> ObjectTemplate -> find ( 'first' , array (
'conditions' => array (
'ObjectTemplate.uuid' => $object [ 'Object' ][ 'template_uuid' ],
'ObjectTemplate.version >' => $object [ 'Object' ][ 'template_version' ],
),
'recursive' => - 1 ,
'contain' => array (
'ObjectTemplateElement'
),
'order' => array ( 'ObjectTemplate.version DESC' )
));
if ( ! empty ( $newer_template )) {
$toReturn [ 'newer_template_version' ] = $newer_template [ 'ObjectTemplate' ][ 'version' ];
// ignore IDs for comparison
$cur_template_temp = Hash :: remove ( Hash :: remove ( $template [ 'ObjectTemplateElement' ], '{n}.id' ), '{n}.object_template_id' );
$newer_template_temp = Hash :: remove ( Hash :: remove ( $newer_template [ 'ObjectTemplateElement' ], '{n}.id' ), '{n}.object_template_id' );
$template_difference = array ();
// check how current template is included in the newer
foreach ( $cur_template_temp as $cur_obj_rel ) {
$flag_sim = false ;
foreach ( $newer_template_temp as $newer_obj_rel ) {
$tmp = Hash :: diff ( $cur_obj_rel , $newer_obj_rel );
if ( count ( $tmp ) == 0 ) {
$flag_sim = true ;
break ;
}
}
if ( ! $flag_sim ) {
$template_difference [] = $cur_obj_rel ;
}
}
$toReturn [ 'updateable_attribute' ] = $object [ 'Attribute' ];
$toReturn [ 'not_updateable_attribute' ] = array ();
} else {
$toReturn [ 'newer_template_version' ] = false ;
}
if ( ! empty ( $template_difference )) { // older template not completely embeded in newer
foreach ( $template_difference as $temp_diff_element ) {
foreach ( $object [ 'Attribute' ] as $i => $attribute ) {
if (
$attribute [ 'object_relation' ] == $temp_diff_element [ 'object_relation' ]
&& $attribute [ 'type' ] == $temp_diff_element [ 'type' ]
) { // This attribute cannot be merged automatically
$attribute [ 'merge-possible' ] = false ;
$toReturn [ 'not_updateable_attribute' ][] = $attribute ;
unset ( $toReturn [ 'updateable_attribute' ][ $i ]);
}
}
}
}
if ( $update_template_available ) { // template version bump requested
$toReturn [ 'template' ] = $newer_template ; // bump the template version
}
}
return $toReturn ;
}
2020-03-30 08:37:16 +02:00
public function reviseObject ( $revised_object , $object , $template ) {
2020-01-17 10:11:51 +01:00
$revised_object_both = array ( 'mergeable' => array (), 'notMergeable' => array ());
// Loop through attributes to inject and perform the correct action
// (inject, duplicate, add warnings, ...) when applicable
foreach ( $revised_object [ 'Attribute' ] as $attribute_to_inject ) {
$flag_no_collision = true ;
foreach ( $object [ 'Attribute' ] as $attribute ) {
if (
$attribute [ 'object_relation' ] == $attribute_to_inject [ 'object_relation' ]
&& $attribute [ 'type' ] == $attribute_to_inject [ 'type' ]
&& $attribute [ 'value' ] !== $attribute_to_inject [ 'value' ]
) { // Collision on value
$multiple = ! empty ( Hash :: extract ( $template [ 'ObjectTemplateElement' ], sprintf ( '{n}[object_relation=%s][type=%s][multiple=true]' , $attribute [ 'object_relation' ], $attribute [ 'type' ])));
if ( $multiple ) { // if multiple is set, check if an entry exists already
$flag_entry_exists = false ;
foreach ( $object [ 'Attribute' ] as $attr ) {
if (
$attr [ 'object_relation' ] == $attribute_to_inject [ 'object_relation' ]
&& $attr [ 'type' ] == $attribute_to_inject [ 'type' ]
&& $attr [ 'value' ] === $attribute_to_inject [ 'value' ]
) {
$flag_entry_exists = true ;
break ;
}
}
if ( ! $flag_entry_exists ) { // entry does no exists, can be duplicated
$attribute_to_inject [ 'is_multiple' ] = true ;
$revised_object_both [ 'mergeable' ][] = $attribute_to_inject ;
$object [ 'Attribute' ][] = $attribute_to_inject ;
}
} else { // Collision on value, multiple not set => propose overwrite
$attribute_to_inject [ 'current_value' ] = $attribute [ 'value' ];
$attribute_to_inject [ 'merge-possible' ] = true ; // the user can still swap value
$revised_object_both [ 'notMergeable' ][] = $attribute_to_inject ;
}
$flag_no_collision = false ;
} else if (
$attribute [ 'object_relation' ] == $attribute_to_inject [ 'object_relation' ]
&& $attribute [ 'type' ] == $attribute_to_inject [ 'type' ]
&& $attribute [ 'value' ] === $attribute_to_inject [ 'value' ]
) { // all good, they are basically the same, do nothing
$revised_object_both [ 'mergeable' ][] = $attribute_to_inject ;
$flag_no_collision = false ;
}
}
if ( $flag_no_collision ) { // no collision, nor equalities => inject it straight away
$revised_object_both [ 'mergeable' ][] = $attribute_to_inject ;
$object [ 'Attribute' ][] = $attribute_to_inject ;
}
}
return array (
'object' => $object ,
'revised_object_both' => $revised_object_both
);
}
2020-02-29 08:57:32 +01:00
public function restSearch ( $user , $returnFormat , $filters , $paramsOnly = false , $jobId = false , & $elementCounter = 0 , & $renderView = false )
{
if ( ! isset ( $this -> validFormats [ $returnFormat ][ 1 ])) {
throw new NotFoundException ( 'Invalid output format.' );
}
App :: uses ( $this -> validFormats [ $returnFormat ][ 1 ], 'Export' );
$exportTool = new $this -> validFormats [ $returnFormat ][ 1 ]();
if ( empty ( $exportTool -> non_restrictive_export )) {
if ( ! isset ( $filters [ 'to_ids' ])) {
$filters [ 'to_ids' ] = 1 ;
}
if ( ! isset ( $filters [ 'published' ])) {
$filters [ 'published' ] = 1 ;
}
$filters [ 'allow_proposal_blocking' ] = 1 ;
}
if ( ! empty ( $filters [ 'quickFilter' ])) {
$filters [ 'searchall' ] = $filters [ 'quickFilter' ];
if ( ! empty ( $filters [ 'value' ])) {
unset ( $filters [ 'value' ]);
}
}
if ( ! empty ( $exportTool -> renderView )) {
$renderView = $exportTool -> renderView ;
}
if ( isset ( $filters [ 'searchall' ])) {
if ( ! empty ( $filters [ 'value' ])) {
$filters [ 'wildcard' ] = $filters [ 'value' ];
unset ( $filters [ 'value' ]);
} else {
$filters [ 'wildcard' ] = $filters [ 'searchall' ];
}
}
$subqueryElements = $this -> Event -> harvestSubqueryElements ( $filters );
2020-11-18 12:07:29 +01:00
$filters = $this -> Event -> addFiltersFromSubqueryElements ( $filters , $subqueryElements , $user );
2020-05-29 15:23:27 +02:00
$filters = $this -> Event -> addFiltersFromUserSettings ( $user , $filters );
2020-09-20 18:18:46 +02:00
$conditions = $this -> buildFilterConditions ( $filters );
2020-02-29 08:57:32 +01:00
$params = array (
2020-09-20 18:18:46 +02:00
'conditions' => $conditions ,
'fields' => array ( 'Attribute.*' , 'Event.org_id' , 'Event.distribution' , 'Object.*' ),
'withAttachments' => ! empty ( $filters [ 'withAttachments' ]) ? $filters [ 'withAttachments' ] : 0 ,
'enforceWarninglist' => ! empty ( $filters [ 'enforceWarninglist' ]) ? $filters [ 'enforceWarninglist' ] : 0 ,
'includeAllTags' => ! empty ( $filters [ 'includeAllTags' ]) ? $filters [ 'includeAllTags' ] : 0 ,
'includeEventUuid' => ! empty ( $filters [ 'includeEventUuid' ]) ? $filters [ 'includeEventUuid' ] : 0 ,
'includeEventTags' => ! empty ( $filters [ 'includeEventTags' ]) ? $filters [ 'includeEventTags' ] : 0 ,
'includeProposals' => ! empty ( $filters [ 'includeProposals' ]) ? $filters [ 'includeProposals' ] : 0 ,
'includeWarninglistHits' => ! empty ( $filters [ 'includeWarninglistHits' ]) ? $filters [ 'includeWarninglistHits' ] : 0 ,
'includeContext' => ! empty ( $filters [ 'includeContext' ]) ? $filters [ 'includeContext' ] : 0 ,
'includeSightings' => ! empty ( $filters [ 'includeSightings' ]) ? $filters [ 'includeSightings' ] : 0 ,
'includeSightingdb' => ! empty ( $filters [ 'includeSightingdb' ]) ? $filters [ 'includeSightingdb' ] : 0 ,
'includeCorrelations' => ! empty ( $filters [ 'includeCorrelations' ]) ? $filters [ 'includeCorrelations' ] : 0 ,
'includeDecayScore' => ! empty ( $filters [ 'includeDecayScore' ]) ? $filters [ 'includeDecayScore' ] : 0 ,
'includeFullModel' => ! empty ( $filters [ 'includeFullModel' ]) ? $filters [ 'includeFullModel' ] : 0 ,
'allow_proposal_blocking' => ! empty ( $filters [ 'allow_proposal_blocking' ]) ? $filters [ 'allow_proposal_blocking' ] : 0 ,
'metadata' => ! empty ( $filters [ 'metadata' ]) ? $filters [ 'metadata' ] : 0 ,
2020-02-29 08:57:32 +01:00
);
if ( ! empty ( $filters [ 'attackGalaxy' ])) {
$params [ 'attackGalaxy' ] = $filters [ 'attackGalaxy' ];
}
if ( isset ( $filters [ 'include_event_uuid' ])) {
$params [ 'includeEventUuid' ] = $filters [ 'include_event_uuid' ];
}
if ( isset ( $filters [ 'limit' ])) {
$params [ 'limit' ] = $filters [ 'limit' ];
if ( ! isset ( $filters [ 'page' ])) {
$filters [ 'page' ] = 1 ;
}
}
if ( isset ( $filters [ 'page' ])) {
$params [ 'page' ] = $filters [ 'page' ];
}
if ( ! empty ( $filters [ 'deleted' ])) {
$params [ 'deleted' ] = $filters [ 'deleted' ];
}
if ( ! empty ( $filters [ 'excludeDecayed' ])) {
$params [ 'excludeDecayed' ] = $filters [ 'excludeDecayed' ];
$params [ 'includeDecayScore' ] = 1 ;
}
if ( ! empty ( $filters [ 'decayingModel' ])) {
$params [ 'decayingModel' ] = $filters [ 'decayingModel' ];
}
if ( ! empty ( $filters [ 'modelOverrides' ])) {
$params [ 'modelOverrides' ] = $filters [ 'modelOverrides' ];
}
if ( ! empty ( $filters [ 'score' ])) {
$params [ 'score' ] = $filters [ 'score' ];
}
2020-05-06 09:32:44 +02:00
if ( ! empty ( $filters [ 'metadata' ])) {
$params [ 'metadata' ] = $filters [ 'metadata' ];
}
2020-02-29 08:57:32 +01:00
if ( $paramsOnly ) {
return $params ;
}
if ( method_exists ( $exportTool , 'modify_params' )) {
$params = $exportTool -> modify_params ( $user , $params );
}
$exportToolParams = array (
'user' => $user ,
'params' => $params ,
'returnFormat' => $returnFormat ,
'scope' => 'Object' ,
'filters' => $filters
);
if ( ! empty ( $exportTool -> additional_params )) {
$params = array_merge_recursive (
$params ,
$exportTool -> additional_params
);
}
2020-06-19 16:21:53 +02:00
$tmpfile = new TmpFileTool ();
$tmpfile -> write ( $exportTool -> header ( $exportToolParams ));
2020-02-29 08:57:32 +01:00
$loop = false ;
if ( empty ( $params [ 'limit' ])) {
$memory_in_mb = $this -> convert_to_memory_limit_to_mb ( ini_get ( 'memory_limit' ));
$default_attribute_memory_coefficient = Configure :: check ( 'MISP.default_attribute_memory_coefficient' ) ? Configure :: read ( 'MISP.default_attribute_memory_coefficient' ) : 80 ;
$memory_scaling_factor = isset ( $exportTool -> memory_scaling_factor ) ? $exportTool -> memory_scaling_factor : $default_attribute_memory_coefficient ;
$params [ 'limit' ] = $memory_in_mb * $memory_scaling_factor / 10 ;
$loop = true ;
$params [ 'page' ] = 1 ;
}
$this -> __iteratedFetch ( $user , $params , $loop , $tmpfile , $exportTool , $exportToolParams , $elementCounter );
2020-06-19 16:21:53 +02:00
$tmpfile -> write ( $exportTool -> footer ( $exportToolParams ));
2020-10-25 09:44:01 +01:00
return $tmpfile ;
2020-02-29 08:57:32 +01:00
}
2020-06-19 16:21:53 +02:00
private function __iteratedFetch ( $user , & $params , & $loop , TmpFileTool $tmpfile , $exportTool , $exportToolParams , & $elementCounter = 0 )
2020-02-29 08:57:32 +01:00
{
$continue = true ;
while ( $continue ) {
2020-05-07 07:58:51 +02:00
$temp = '' ;
2020-09-01 15:59:38 +02:00
$this -> Allowedlist = ClassRegistry :: init ( 'Allowedlist' );
2020-02-29 08:57:32 +01:00
$results = $this -> fetchObjects ( $user , $params , $continue );
2020-05-06 14:22:05 +02:00
if ( empty ( $results )) {
$loop = false ;
return true ;
}
2020-05-07 07:58:51 +02:00
if ( $elementCounter !== 0 && ! empty ( $results )) {
$temp .= $exportTool -> separator ( $exportToolParams );
}
2020-02-29 08:57:32 +01:00
if ( $params [ 'includeSightingdb' ]) {
$this -> Sightingdb = ClassRegistry :: init ( 'Sightingdb' );
$results = $this -> Sightingdb -> attachToObjects ( $results , $user );
}
$params [ 'page' ] += 1 ;
2020-09-01 15:59:38 +02:00
$results = $this -> Allowedlist -> removeAllowedlistedFromArray ( $results , true );
2020-02-29 08:57:32 +01:00
$results = array_values ( $results );
$i = 0 ;
foreach ( $results as $object ) {
$elementCounter ++ ;
$handlerResult = $exportTool -> handler ( $object , $exportToolParams );
$temp .= $handlerResult ;
if ( $handlerResult !== '' ) {
if ( $i != count ( $results ) - 1 ) {
$temp .= $exportTool -> separator ( $exportToolParams );
}
}
$i ++ ;
}
if ( ! $loop ) {
$continue = false ;
}
2020-06-19 16:21:53 +02:00
$tmpfile -> write ( $temp );
2020-02-29 08:57:32 +01:00
}
return true ;
}
2020-11-11 09:56:05 +01:00
private function attributeValueDifferent ( $newValue , $originalValue , $field )
{
if ( in_array ( $field , [ 'first_seen' , 'last_seen' ])) {
return new DateTime ( $newValue ) != new DateTime ( $originalValue );
} else {
return $newValue != $originalValue ;
}
}
2017-06-13 12:08:26 +02:00
}