2013-03-04 18:05:17 +01:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
App :: uses ( 'Folder' , 'Utility' );
App :: uses ( 'File' , 'Utility' );
2020-05-05 15:23:26 +02:00
App :: uses ( 'AttachmentTool' , 'Tools' );
2013-03-04 18:05:17 +01:00
2019-10-06 13:05:29 +02:00
/**
* @ property Attribute $Attribute
*/
2018-07-19 11:48:22 +02:00
class AttributesController extends AppController
{
2020-05-12 22:35:00 +02:00
public $components = array ( 'Security' , 'RequestHandler' );
2018-07-19 11:48:22 +02:00
public $paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 ,
'conditions' => array ( 'AND' => array ( 'Attribute.deleted' => 0 )),
'order' => 'Attribute.event_id DESC'
);
public function beforeFilter ()
{
parent :: beforeFilter ();
$this -> Auth -> allow ( 'restSearch' );
$this -> Auth -> allow ( 'returnAttributes' );
$this -> Auth -> allow ( 'downloadAttachment' );
$this -> Auth -> allow ( 'text' );
$this -> Auth -> allow ( 'rpz' );
$this -> Auth -> allow ( 'bro' );
// permit reuse of CSRF tokens on the search page.
2021-09-14 15:24:30 +02:00
if ( 'search' === $this -> request -> params [ 'action' ]) {
2018-07-19 11:48:22 +02:00
$this -> Security -> csrfCheck = false ;
}
2020-07-31 10:07:19 +02:00
$this -> Security -> unlockedActions [] = 'getMassEditForm' ;
2021-04-27 09:45:11 +02:00
$this -> Security -> unlockedActions [] = 'search' ;
2021-09-14 15:24:30 +02:00
if ( $this -> request -> action === 'add_attachment' ) {
2018-07-19 11:48:22 +02:00
$this -> Security -> disabledFields = array ( 'values' );
}
$this -> Security -> validatePost = true ;
// convert uuid to id if present in the url and overwrite id field
2021-09-14 15:24:30 +02:00
if ( isset ( $this -> request -> params -> query [ 'uuid' ])) {
2018-07-19 11:48:22 +02:00
$params = array (
2021-09-14 15:24:30 +02:00
'conditions' => array ( 'Attribute.uuid' => $this -> request -> params -> query [ 'uuid' ]),
2018-07-19 11:48:22 +02:00
'recursive' => 0 ,
'fields' => 'Attribute.id'
);
$result = $this -> Attribute -> find ( 'first' , $params );
if ( isset ( $result [ 'Attribute' ]) && isset ( $result [ 'Attribute' ][ 'id' ])) {
$id = $result [ 'Attribute' ][ 'id' ];
$this -> params -> addParams ( array ( 'pass' => array ( $id ))); // FIXME find better way to change id variable if uuid is found. params->url and params->here is not modified accordingly now
}
}
// do not show private to other orgs
if ( ! $this -> _isSiteAdmin ()) {
$this -> paginate = Set :: merge ( $this -> paginate , array ( 'conditions' => $this -> Attribute -> buildConditions ( $this -> Auth -> user ())));
}
}
public function index ()
{
$this -> Attribute -> recursive = - 1 ;
2019-08-01 11:12:59 +02:00
$this -> paginate [ 'recursive' ] = - 1 ;
$this -> paginate [ 'contain' ] = array (
'Event' => array (
'fields' => array ( 'Event.id' , 'Event.orgc_id' , 'Event.org_id' , 'Event.info' , 'Event.user_id' , 'Event.date' ),
),
2021-11-06 11:44:13 +01:00
'AttributeTag' ,
2019-08-01 11:12:59 +02:00
'Object' => array (
'fields' => array ( 'Object.id' , 'Object.distribution' , 'Object.sharing_group_id' )
2020-07-27 22:00:31 +02:00
),
'SharingGroup' => [ 'fields' => [ 'SharingGroup.name' ]],
2019-08-01 11:12:59 +02:00
);
2018-07-19 11:48:22 +02:00
$this -> set ( 'isSearch' , 0 );
$attributes = $this -> paginate ();
2021-11-06 11:44:13 +01:00
$this -> Attribute -> attachTagsToAttributes ( $attributes , [ 'includeAllTags' => true ]);
2018-07-19 11:48:22 +02:00
if ( $this -> _isRest ()) {
2021-11-06 11:44:13 +01:00
$attributes = array_column ( $attributes , 'Attribute' );
2018-07-19 11:48:22 +02:00
return $this -> RestResponse -> viewData ( $attributes , $this -> response -> type ());
}
2020-12-10 13:45:56 +01:00
$orgTable = $this -> Attribute -> Event -> Orgc -> find ( 'all' , [
'fields' => [ 'Orgc.id' , 'Orgc.name' , 'Orgc.uuid' ],
]);
$orgTable = Hash :: combine ( $orgTable , '{n}.Orgc.id' , '{n}.Orgc' );
2020-11-22 19:14:25 +01:00
foreach ( $attributes as & $attribute ) {
if ( isset ( $orgTable [ $attribute [ 'Event' ][ 'orgc_id' ]])) {
2020-12-10 13:45:56 +01:00
$attribute [ 'Event' ][ 'Orgc' ] = $orgTable [ $attribute [ 'Event' ][ 'orgc_id' ]];
2020-11-22 19:14:25 +01:00
}
}
2020-12-10 13:45:56 +01:00
2020-11-22 19:14:25 +01:00
list ( $attributes , $sightingsData ) = $this -> __searchUI ( $attributes );
$this -> set ( 'sightingsData' , $sightingsData );
2020-12-10 13:45:56 +01:00
$this -> set ( 'orgTable' , array_column ( $orgTable , 'name' , 'id' ));
2018-11-23 14:11:33 +01:00
$this -> set ( 'shortDist' , $this -> Attribute -> shortDist );
2018-07-19 11:48:22 +02:00
$this -> set ( 'attributes' , $attributes );
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
2021-07-29 15:59:26 +02:00
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
2018-07-19 11:48:22 +02:00
}
public function add ( $eventId = false )
{
if ( $this -> request -> is ( 'get' ) && $this -> _isRest ()) {
return $this -> RestResponse -> describe ( 'Attributes' , 'add' , false , $this -> response -> type ());
}
if ( $eventId === false ) {
throw new MethodNotAllowedException ( __ ( 'No event ID set.' ));
}
2020-12-05 14:26:38 +01:00
$event = $this -> Attribute -> Event -> fetchSimpleEvent ( $this -> Auth -> user (), $eventId , [ 'contain' => [ 'Orgc' ]]);
2020-07-20 10:10:47 +02:00
if ( ! $event ) {
2018-07-19 11:48:22 +02:00
throw new NotFoundException ( __ ( 'Invalid event' ));
}
2020-07-20 10:10:47 +02:00
if ( ! $this -> __canModifyEvent ( $event )) {
2019-07-10 11:57:21 +02:00
throw new ForbiddenException ( __ ( 'You do not have permission to do that.' ));
2018-07-19 11:48:22 +02:00
}
if ( ! $this -> _isRest ()) {
2020-08-06 11:52:53 +02:00
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
if ( $this -> request -> is ( 'ajax' )) {
$this -> set ( 'ajax' , true );
$this -> layout = 'ajax' ;
} else {
$this -> set ( 'ajax' , false );
}
if ( $this -> request -> is ( 'post' )) {
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
}
if ( ! isset ( $this -> request -> data [ 'Attribute' ])) {
$this -> request -> data = array ( 'Attribute' => $this -> request -> data );
}
2020-05-07 12:37:32 +02:00
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'distribution' ]) && $this -> request -> data [ 'Attribute' ][ 'distribution' ] == 4 ) {
2020-08-06 11:52:53 +02:00
if ( ! $this -> __canUseSharingGroup ( $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ])) {
2020-08-05 22:39:17 +02:00
throw new ForbiddenException ( __ ( 'Invalid Sharing Group or not authorised.' ));
2020-04-20 09:43:53 +02:00
}
}
2018-07-19 11:48:22 +02:00
//
// multiple attributes in batch import
//
if ( ! empty ( $this -> request -> data [ 'Attribute' ][ 'batch_import' ]) || ( ! empty ( $this -> request -> data [ 'Attribute' ][ 'value' ]) && is_array ( $this -> request -> data [ 'Attribute' ][ 'value' ]))) {
$attributes = array ();
if ( is_array ( $this -> request -> data [ 'Attribute' ][ 'value' ])) {
$values = $this -> request -> data [ 'Attribute' ][ 'value' ];
} else {
$values = explode ( " \n " , $this -> request -> data [ 'Attribute' ][ 'value' ]);
}
2018-11-23 14:11:33 +01:00
$temp = $this -> request -> data [ 'Attribute' ];
2018-07-19 11:48:22 +02:00
foreach ( $values as $value ) {
2018-11-13 11:48:12 +01:00
$temp [ 'value' ] = $value ;
$attributes [] = $temp ;
2018-07-19 11:48:22 +02:00
}
} else {
$attributes = $this -> request -> data [ 'Attribute' ];
}
if ( ! isset ( $attributes [ 0 ])) {
$attributes = array ( 0 => $attributes );
}
$fails = array ();
$successes = 0 ;
$attributeCount = count ( $attributes );
2019-08-06 15:55:16 +02:00
$inserted_ids = array ();
2018-07-19 11:48:22 +02:00
foreach ( $attributes as $k => $attribute ) {
2019-08-06 15:55:16 +02:00
$validationErrors = array ();
2021-10-10 14:48:29 +02:00
$this -> Attribute -> captureAttribute ( $attribute , $event [ 'Event' ][ 'id' ], $this -> Auth -> user (), false , false , $event , $validationErrors , $this -> params [ 'named' ]);
2019-08-06 15:55:16 +02:00
if ( empty ( $validationErrors )) {
2019-08-06 16:01:09 +02:00
$inserted_ids [] = $this -> Attribute -> id ;
2021-10-10 14:48:29 +02:00
$successes ++ ;
2018-07-19 11:48:22 +02:00
} else {
2019-08-06 15:55:16 +02:00
$fails [ " attribute_ " . $k ] = $validationErrors ;
2018-07-19 11:48:22 +02:00
}
}
2021-10-10 14:48:29 +02:00
if ( $successes !== 0 ) {
2020-08-06 11:52:53 +02:00
$this -> Attribute -> Event -> unpublishEvent ( $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
if ( $this -> _isRest ()) {
2021-10-10 14:48:29 +02:00
if ( $successes !== 0 ) {
2018-07-19 11:48:22 +02:00
$attributes = $this -> Attribute -> find ( 'all' , array (
'recursive' => - 1 ,
2019-08-06 15:55:16 +02:00
'conditions' => array ( 'Attribute.id' => $inserted_ids ),
2019-07-30 12:03:49 +02:00
'contain' => array (
'AttributeTag' => array (
'Tag' => array ( 'fields' => array ( 'Tag.id' , 'Tag.name' , 'Tag.colour' , 'Tag.numerical_value' ))
)
)
2018-07-19 11:48:22 +02:00
));
2021-10-10 14:48:29 +02:00
if ( count ( $attributes ) === 1 ) {
2018-07-19 11:48:22 +02:00
$attributes = $attributes [ 0 ];
2019-08-06 16:33:16 +02:00
} else {
$result = array ( 'Attribute' => array ());
foreach ( $attributes as $attribute ) {
$temp = $attribute [ 'Attribute' ];
if ( ! empty ( $attribute [ 'AttributeTag' ])) {
foreach ( $attribute [ 'AttributeTag' ] as $at ) {
$temp [ 'Tag' ][] = $at [ 'Tag' ];
}
}
$result [ 'Attribute' ][] = $temp ;
}
$attributes = $result ;
unset ( $result );
2018-07-19 11:48:22 +02:00
}
return $this -> RestResponse -> viewData ( $attributes , $this -> response -> type (), $fails );
} else {
if ( $attributeCount == 1 ) {
return $this -> RestResponse -> saveFailResponse ( 'Attributes' , 'add' , false , $fails [ " attribute_0 " ], $this -> response -> type ());
} else {
return $this -> RestResponse -> saveFailResponse ( 'Attributes' , 'add' , false , $fails , $this -> response -> type ());
}
}
} else {
if ( empty ( $fails )) {
$message = 'Attributes saved.' ;
} else {
2018-11-13 11:48:12 +01:00
if ( $attributeCount > 1 ) {
2018-07-19 11:48:22 +02:00
$failKeys = array_keys ( $fails );
foreach ( $failKeys as $k => $v ) {
$v = explode ( '_' , $v );
2018-11-13 11:48:12 +01:00
$failKeys [ $k ] = intval ( $v [ 1 ]);
2018-07-19 11:48:22 +02:00
}
2018-11-23 14:11:33 +01:00
$failed = 1 ;
2018-11-13 11:48:12 +01:00
$message = sprintf ( 'Attributes saved, however, %s attributes could not be saved. Click %s for more info' , count ( $fails ), '$flashErrorMessage' );
2018-07-19 11:48:22 +02:00
} else {
2019-12-07 00:34:52 +01:00
$failed = 1 ;
$message = 'Attribute could not be saved.' ;
2018-07-19 11:48:22 +02:00
}
}
2018-11-23 14:11:33 +01:00
if ( ! empty ( $failKeys )) {
$flashErrorMessage = array ();
$original_values = trim ( $this -> request -> data [ 'Attribute' ][ 'value' ]);
$original_values = explode ( " \n " , $original_values );
foreach ( $original_values as $k => $original_value ) {
$original_value = trim ( $original_value );
if ( in_array ( $k , $failKeys )) {
$reason = '' ;
foreach ( $fails [ " attribute_ " . $k ] as $failKey => $failData ) {
$reason = $failKey . ': ' . $failData [ 0 ];
}
$flashErrorMessage [] = '<span class="red bold">' . h ( $original_value ) . '</span> (' . h ( $reason ) . ')' ;
} else {
$flashErrorMessage [] = '<span class="green bold">' . h ( $original_value ) . '</span>' ;
}
}
$flashErrorMessage = implode ( '<br />' , $flashErrorMessage );
$this -> Session -> write ( 'flashErrorMessage' , $flashErrorMessage );
}
2019-12-10 11:35:23 +01:00
if ( empty ( $failed )) {
$this -> Flash -> success ( $message );
} else {
$this -> Flash -> error ( $message );
}
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
2019-12-10 11:35:23 +01:00
$this -> layout = false ;
2018-07-19 11:48:22 +02:00
$errors = ( $attributeCount > 1 ) ? $message : $this -> Attribute -> validationErrors ;
if ( ! empty ( $successes )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $message )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $errors )), 'status' => 200 , 'type' => 'json' ));
}
} else {
2018-08-21 13:26:37 +02:00
if ( $successes > 0 ) {
2020-07-20 10:10:47 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $event [ 'Event' ][ 'id' ]));
2018-07-19 11:48:22 +02:00
}
}
}
}
// combobox for types
$types = array_keys ( $this -> Attribute -> typeDefinitions );
foreach ( $types as $key => $value ) {
if ( in_array ( $value , array ( 'malware-sample' , 'attachment' ))) {
unset ( $types [ $key ]);
}
}
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = array_keys ( $this -> Attribute -> categoryDefinitions );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
2020-07-04 10:38:50 +02:00
$this -> set ( 'categories' , $categories );
2018-07-19 11:48:22 +02:00
2021-10-10 14:48:29 +02:00
$sgs = $this -> Attribute -> SharingGroup -> fetchAllAuthorised ( $this -> Auth -> user (), 'name' , true );
2018-07-19 11:48:22 +02:00
$this -> set ( 'sharingGroups' , $sgs );
2021-10-09 23:32:51 +02:00
$this -> set ( 'initialDistribution' , $this -> Attribute -> defaultDistribution ());
2019-12-10 09:28:54 +01:00
$fieldDesc = array ();
2018-07-19 11:48:22 +02:00
$distributionLevels = $this -> Attribute -> distributionLevels ;
if ( empty ( $sgs )) {
unset ( $distributionLevels [ 4 ]);
}
$this -> set ( 'distributionLevels' , $distributionLevels );
2019-12-10 09:28:54 +01:00
foreach ( $distributionLevels as $key => $value ) {
$fieldDesc [ 'distribution' ][ $key ] = $this -> Attribute -> distributionDescriptions [ $key ][ 'formdesc' ];
}
2018-07-19 11:48:22 +02:00
foreach ( $this -> Attribute -> categoryDefinitions as $key => $value ) {
2019-12-10 09:28:54 +01:00
$fieldDesc [ 'category' ][ $key ] = isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ];
2018-07-19 11:48:22 +02:00
}
foreach ( $this -> Attribute -> typeDefinitions as $key => $value ) {
2019-12-10 09:28:54 +01:00
$fieldDesc [ 'type' ][ $key ] = isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ];
2018-07-19 11:48:22 +02:00
}
$this -> loadModel ( 'Noticelist' );
$notice_list_triggers = $this -> Noticelist -> getTriggerData ();
2020-08-05 19:52:54 +02:00
$this -> set ( 'notice_list_triggers' , json_encode ( $notice_list_triggers ));
2019-12-10 09:28:54 +01:00
$this -> set ( 'fieldDesc' , $fieldDesc );
2018-07-19 11:48:22 +02:00
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
2020-08-05 19:52:54 +02:00
$this -> set ( 'event' , $event );
2021-10-10 14:48:29 +02:00
$this -> set ( 'action' , $this -> request -> action );
2018-07-19 11:48:22 +02:00
}
public function download ( $id = null )
{
2020-07-20 10:10:47 +02:00
$conditions = $this -> __idToConditions ( $id );
2020-06-29 14:10:23 +02:00
$conditions [ 'Attribute.type' ] = array ( 'attachment' , 'malware-sample' );
$attributes = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => $conditions , 'flatten' => true ));
if ( empty ( $attributes )) {
throw new UnauthorizedException ( __ ( 'Attribute does not exists or you do not have the permission to download this attribute.' ));
2018-07-19 11:48:22 +02:00
}
2020-06-29 14:10:23 +02:00
$this -> __downloadAttachment ( $attributes [ 0 ][ 'Attribute' ]);
2018-07-19 11:48:22 +02:00
}
private function __downloadAttachment ( $attribute )
{
2020-08-13 15:58:42 +02:00
$file = $this -> Attribute -> getAttachmentFile ( $attribute );
2018-08-15 15:56:14 +02:00
2018-07-19 11:48:22 +02:00
if ( 'attachment' == $attribute [ 'type' ]) {
$filename = $attribute [ 'value' ];
$fileExt = pathinfo ( $filename , PATHINFO_EXTENSION );
$filename = substr ( $filename , 0 , strlen ( $filename ) - strlen ( $fileExt ) - 1 );
} elseif ( 'malware-sample' == $attribute [ 'type' ]) {
$filenameHash = explode ( '|' , $attribute [ 'value' ]);
$filename = substr ( $filenameHash [ 0 ], strrpos ( $filenameHash [ 0 ], '\\' ));
$fileExt = " zip " ;
} else {
throw new NotFoundException ( __ ( 'Attribute not an attachment or malware-sample' ));
}
$this -> autoRender = false ;
$this -> response -> type ( $fileExt );
$download_attachments_on_load = Configure :: check ( 'MISP.download_attachments_on_load' ) ? Configure :: read ( 'MISP.download_attachments_on_load' ) : true ;
2020-05-05 15:23:26 +02:00
$this -> response -> file ( $file -> path , array ( 'download' => $download_attachments_on_load , 'name' => $filename . '.' . $fileExt ));
2018-07-19 11:48:22 +02:00
}
public function add_attachment ( $eventId = null )
{
2020-12-05 14:26:38 +01:00
$event = $this -> Attribute -> Event -> fetchSimpleEvent ( $this -> Auth -> user (), $eventId , [ 'contain' => [ 'Orgc' ]]);
2020-07-20 10:10:47 +02:00
if ( empty ( $event )) {
throw new NotFoundException ( __ ( 'Invalid Event.' ));
}
if ( ! $this -> __canModifyEvent ( $event )) {
throw new ForbiddenException ( __ ( 'You do not have permission to do that.' ));
}
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'post' )) {
2020-08-06 11:52:53 +02:00
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'distribution' ]) && $this -> request -> data [ 'Attribute' ][ 'distribution' ] == 4 ) {
if ( ! $this -> __canUseSharingGroup ( $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ])) {
throw new ForbiddenException ( __ ( 'Invalid Sharing Group or not authorised.' ));
}
2018-07-19 11:48:22 +02:00
}
2020-08-06 11:52:53 +02:00
2018-07-19 11:48:22 +02:00
$fails = array ();
$success = 0 ;
2019-10-06 13:05:29 +02:00
foreach ( $this -> request -> data [ 'Attribute' ][ 'values' ] as $value ) {
2018-07-19 11:48:22 +02:00
// Check if there were problems with the file upload
// only keep the last part of the filename, this should prevent directory attacks
$filename = basename ( $value [ 'name' ]);
$tmpfile = new File ( $value [ 'tmp_name' ]);
if (( isset ( $value [ 'error' ]) && $value [ 'error' ] == 0 ) ||
( ! empty ( $value [ 'tmp_name' ]) && $value [ 'tmp_name' ] != 'none' )
) {
if ( ! is_uploaded_file ( $tmpfile -> path )) {
throw new InternalErrorException ( __ ( 'PHP says file was not uploaded. Are you attacking me?' ));
}
} else {
$fails [] = $filename ;
continue ;
}
if ( $this -> request -> data [ 'Attribute' ][ 'malware' ]) {
if ( $this -> request -> data [ 'Attribute' ][ 'advanced' ]) {
$result = $this -> Attribute -> advancedAddMalwareSample (
2020-07-20 10:10:47 +02:00
$event [ 'Event' ][ 'id' ],
2018-07-19 11:48:22 +02:00
$this -> request -> data [ 'Attribute' ],
$filename ,
$tmpfile
);
} else {
$result = $this -> Attribute -> simpleAddMalwareSample (
2020-07-20 10:10:47 +02:00
$event [ 'Event' ][ 'id' ],
2018-07-19 11:48:22 +02:00
$this -> request -> data [ 'Attribute' ],
$filename ,
$tmpfile
);
}
2019-10-06 10:29:20 +02:00
if ( $result ) {
$success ++ ;
} else {
$fails [] = $filename ;
}
2018-07-19 11:48:22 +02:00
if ( ! empty ( $result )) {
foreach ( $result [ 'Object' ] as $object ) {
$object [ 'distribution' ] = $this -> request -> data [ 'Attribute' ][ 'distribution' ];
if ( ! empty ( $this -> request -> data [ 'sharing_group_id' ])) {
$object [ 'sharing_group_id' ] = $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ];
}
foreach ( $object [ 'Attribute' ] as $ka => $attribute ) {
$object [ 'Attribute' ][ $ka ][ 'distribution' ] = 5 ;
}
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Object -> captureObject ( array ( 'Object' => $object ), $event [ 'Event' ][ 'id' ], $this -> Auth -> user ());
2018-07-19 11:48:22 +02:00
}
if ( ! empty ( $result [ 'ObjectReference' ])) {
foreach ( $result [ 'ObjectReference' ] as $reference ) {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Object -> ObjectReference -> smartSave ( $reference , $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
}
}
} else {
$attribute = array (
2020-08-06 11:52:53 +02:00
'Attribute' => array (
'value' => $filename ,
'category' => $this -> request -> data [ 'Attribute' ][ 'category' ],
'type' => 'attachment' ,
'event_id' => $event [ 'Event' ][ 'id' ],
2021-10-09 17:07:29 +02:00
'data_raw' => $tmpfile -> read (),
2020-08-06 11:52:53 +02:00
'comment' => $this -> request -> data [ 'Attribute' ][ 'comment' ],
'to_ids' => 0 ,
'distribution' => $this -> request -> data [ 'Attribute' ][ 'distribution' ],
'sharing_group_id' => isset ( $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ]) ? $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ] : 0 ,
)
2018-07-19 11:48:22 +02:00
);
$this -> Attribute -> create ();
$r = $this -> Attribute -> save ( $attribute );
if ( $r == false ) {
$fails [] = $filename ;
} else {
$success ++ ;
}
}
}
2020-08-06 11:52:53 +02:00
$message = __n ( 'The attachment have been uploaded.' , 'The attachments have been uploaded.' , $success );
2018-07-19 11:48:22 +02:00
if ( ! empty ( $fails )) {
2020-04-28 15:42:58 +02:00
$message = __ ( 'Some of the attachments failed to upload. The failed files were: %s - This can be caused by the attachments already existing in the event.' , implode ( ', ' , $fails ));
2018-07-19 11:48:22 +02:00
}
if ( empty ( $success )) {
if ( empty ( $fails )) {
2020-04-28 15:42:58 +02:00
$message = __ ( 'The attachment(s) could not be saved. Please contact your administrator.' );
2018-07-19 11:48:22 +02:00
}
} else {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> unpublishEvent ( $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
if ( empty ( $success ) && ! empty ( $fails )) {
$this -> Flash -> error ( $message );
} else {
$this -> Flash -> success ( $message );
}
if ( ! $this -> _isRest ()) {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
2020-07-20 10:10:47 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $event [ 'Event' ][ 'id' ]));
2018-07-19 11:48:22 +02:00
} else {
// set the event_id in the form
2020-07-20 10:10:47 +02:00
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $event [ 'Event' ][ 'id' ];
2019-10-06 10:29:20 +02:00
}
2018-07-19 11:48:22 +02:00
if ( ! $this -> _isRest ()) {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
}
2019-10-06 10:29:20 +02:00
// Filter categories that contains attachment type
2018-07-19 11:48:22 +02:00
$selectedCategories = array ();
2019-10-06 10:29:20 +02:00
foreach ( $this -> Attribute -> categoryDefinitions as $category => $values ) {
foreach ( $values [ 'types' ] as $type ) {
if ( $this -> Attribute -> typeIsAttachment ( $type )) {
2018-07-19 11:48:22 +02:00
$selectedCategories [] = $category ;
2021-07-20 17:30:17 +02:00
break ;
2018-07-19 11:48:22 +02:00
}
}
}
2021-07-20 17:30:17 +02:00
// Create list of categories that should be marked as malware sample by default
$isMalwareSampleCategory = [];
foreach ( $selectedCategories as $category ) {
$possibleMalwareSample = false ;
foreach ( $this -> Attribute -> categoryDefinitions [ $category ][ 'types' ] as $type ) {
if ( $this -> Attribute -> typeIsMalware ( $type )) {
$possibleMalwareSample = true ;
break ;
}
}
$isMalwareSampleCategory [ $category ] = $possibleMalwareSample ;
}
2018-07-19 11:48:22 +02:00
$categories = $this -> _arrayToValuesIndexArray ( $selectedCategories );
$this -> set ( 'categories' , $categories );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
2021-07-20 17:30:17 +02:00
$this -> set ( 'isMalwareSampleCategory' , $isMalwareSampleCategory );
2019-10-06 13:05:29 +02:00
$this -> set ( 'advancedExtractionAvailable' , $this -> Attribute -> isAdvancedExtractionAvailable ());
2018-07-19 11:48:22 +02:00
// combobox for distribution
2020-04-28 15:42:58 +02:00
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
2020-04-28 17:46:38 +02:00
$this -> set ( 'info' , $this -> __getInfo ());
2018-07-19 11:48:22 +02:00
$this -> loadModel ( 'SharingGroup' );
$sgs = $this -> SharingGroup -> fetchAllAuthorised ( $this -> Auth -> user (), 'name' , 1 );
$this -> set ( 'sharingGroups' , $sgs );
2019-10-06 13:05:29 +02:00
$this -> set ( 'currentDist' , $event [ 'Event' ][ 'distribution' ]);
$this -> set ( 'published' , $event [ 'Event' ][ 'published' ]);
2018-07-19 11:48:22 +02:00
}
// Imports the CSV threatConnect file to multiple attributes
public function add_threatconnect ( $eventId = null )
{
if ( $this -> request -> is ( 'post' )) {
$this -> loadModel ( 'Event' );
$this -> Event -> id = $eventId ;
$this -> Event -> recursive = - 1 ;
$this -> Event -> read ();
2020-07-20 10:10:47 +02:00
if ( ! $this -> __canModifyEvent ( $this -> Event -> data )) {
throw new ForbiddenException ( __ ( 'You do not have permission to do that.' ));
2018-07-19 11:48:22 +02:00
}
//
// File upload
//
// Check if there were problems with the file upload
$tmpfile = new File ( $this -> request -> data [ 'Attribute' ][ 'value' ][ 'tmp_name' ]);
if (( isset ( $this -> request -> data [ 'Attribute' ][ 'value' ][ 'error' ]) && $this -> request -> data [ 'Attribute' ][ 'value' ][ 'error' ] == 0 ) ||
( ! empty ( $this -> request -> data [ 'Attribute' ][ 'value' ][ 'tmp_name' ]) && $this -> request -> data [ 'Attribute' ][ 'value' ][ 'tmp_name' ] != 'none' )
) {
if ( ! is_uploaded_file ( $tmpfile -> path )) {
throw new InternalErrorException ( __ ( 'PHP says file was not uploaded. Are you attacking me?' ));
}
} else {
$this -> Flash -> error ( __ ( 'There was a problem to upload the file.' , true ), 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'attributes' , 'action' => 'add_threatconnect' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
// verify mime type
$file_info = $tmpfile -> info ();
if ( $file_info [ 'mime' ] != 'text/plain' ) {
$this -> Flash -> error ( 'File not in CSV format.' , 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'attributes' , 'action' => 'add_threatconnect' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
// parse uploaded csv file
$filename = $tmpfile -> path ;
$header = null ;
$entries = array ();
if (( $handle = fopen ( $filename , 'r' )) !== false ) {
while (( $row = fgetcsv ( $handle , 0 , ',' , '"' )) !== false ) {
if ( ! $header ) {
$header = $row ;
} else {
$entries [] = array_combine ( $header , $row );
}
}
fclose ( $handle );
}
// verify header of the file (first row)
$required_headers = array ( 'Type' , 'Value' , 'Confidence' , 'Description' , 'Source' );
// TODO i18n
if ( count ( array_intersect ( $header , $required_headers )) != count ( $required_headers )) {
$this -> Flash -> error ( 'Incorrect ThreatConnect headers. The minimum required headers are: ' . implode ( ',' , $required_headers ), 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'attributes' , 'action' => 'add_threatconnect' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
//
// import attributes
//
$attributes = array (); // array with all the attributes we're going to save
foreach ( $entries as $entry ) {
$attribute = array ();
$attribute [ 'event_id' ] = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
$attribute [ 'value' ] = $entry [ 'Value' ];
$attribute [ 'to_ids' ] = ( $entry [ 'Confidence' ] > 51 ) ? 1 : 0 ; // To IDS if high confidence
$attribute [ 'comment' ] = $entry [ 'Description' ];
$attribute [ 'distribution' ] = '3' ; // 'All communities'
if ( Configure :: read ( 'MISP.default_attribute_distribution' ) != null ) {
if ( Configure :: read ( 'MISP.default_attribute_distribution' ) === 'event' ) {
$attribute [ 'distribution' ] = $this -> Event -> data [ 'Event' ][ 'distribution' ];
} else {
$attribute [ 'distribution' ] = Configure :: read ( 'MISP.default_attribute_distribution' );
}
}
switch ( $entry [ 'Type' ]) {
case 'Address' :
$attribute [ 'category' ] = 'Network activity' ;
$attribute [ 'type' ] = 'ip-dst' ;
break ;
case 'Host' :
$attribute [ 'category' ] = 'Network activity' ;
$attribute [ 'type' ] = 'domain' ;
break ;
case 'EmailAddress' :
$attribute [ 'category' ] = 'Payload delivery' ;
$attribute [ 'type' ] = 'email-src' ;
break ;
case 'File' :
$attribute [ 'category' ] = 'Artifacts dropped' ;
$attribute [ 'value' ] = strtolower ( $attribute [ 'value' ]);
if ( preg_match ( " #^[0-9a-f] { 32} $ # " , $attribute [ 'value' ])) {
$attribute [ 'type' ] = 'md5' ;
} elseif ( preg_match ( " #^[0-9a-f] { 40} $ # " , $attribute [ 'value' ])) {
$attribute [ 'type' ] = 'sha1' ;
} elseif ( preg_match ( " #^[0-9a-f] { 64} $ # " , $attribute [ 'value' ])) {
$attribute [ 'type' ] = 'sha256' ;
} else {
// do not keep attributes that do not have a match
$attribute = null ;
}
break ;
case 'URL' :
$attribute [ 'category' ] = 'Network activity' ;
$attribute [ 'type' ] = 'url' ;
break ;
default :
// do not keep attributes that do not have a match
$attribute = null ;
}
// add attribute to the array that will be saved
if ( $attribute ) {
$attributes [] = $attribute ;
}
}
//
// import source info:
//
// 1/ iterate over all the sources, unique
// 2/ add uniques as 'Internal reference'
// 3/ if url format -> 'link'
2018-08-31 13:19:47 +02:00
// else 'comment'
2018-07-19 11:48:22 +02:00
$references = array ();
foreach ( $entries as $entry ) {
if ( empty ( $entry [ 'Source' ])) {
continue ;
}
$references [ $entry [ 'Source' ]] = true ;
}
$references = array_keys ( $references );
// generate the Attributes
foreach ( $references as $reference ) {
$attribute = array ();
$attribute [ 'event_id' ] = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
$attribute [ 'category' ] = 'Internal reference' ;
if ( preg_match ( '#^(http|ftp)(s)?\:\/\/((([a-z|0-9|\-]{1,25})(\.)?){2,7})($|/.*$)#i' , $reference )) {
$attribute [ 'type' ] = 'link' ;
} else {
$attribute [ 'type' ] = 'comment' ;
}
$attribute [ 'value' ] = $reference ;
$attribute [ 'distribution' ] = 3 ; // 'All communities'
// add attribute to the array that will be saved
$attributes [] = $attribute ;
}
//
// finally save all the attributes at once, and continue if there are validation errors
//
$results = array ( 'successes' => 0 , 'fails' => 0 );
foreach ( $attributes as $attribute ) {
$this -> Attribute -> create ();
$result = $this -> Attribute -> save ( $attribute );
if ( ! $result ) {
$results [ 'fails' ] ++ ;
} else {
$results [ 'successes' ] ++ ;
}
}
// data imported (with or without errors)
// remove the published flag from the event
$this -> loadModel ( 'Event' );
$this -> Event -> id = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
$this -> Event -> saveField ( 'published' , 0 );
// everything is done, now redirect to event view
$message = __ ( 'The ThreatConnect data has been imported.' );
if ( $results [ 'successes' ] != 0 ) {
$flashType = 'success' ;
$temp = sprintf ( __ ( '%s entries imported.' ), $results [ 'successes' ]);
$message .= ' ' . $temp ;
}
if ( $results [ 'fails' ] != 0 ) {
$temp = sprintf ( __ ( '%s entries could not be imported.' ), $results [ 'fails' ]);
$message .= ' ' . $temp ;
}
$this -> Flash -> { empty ( $flashType ) ? 'error' : $flashType }( $message );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
} else {
// set the event_id in the form
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
}
// form not submitted, show page
$this -> loadModel ( 'Event' );
$events = $this -> Event -> findById ( $eventId );
$this -> set ( 'published' , $events [ 'Event' ][ 'published' ]);
}
public function edit ( $id = null )
{
if ( $this -> request -> is ( 'get' ) && $this -> _isRest ()) {
return $this -> RestResponse -> describe ( 'Attributes' , 'edit' , false , $this -> response -> type ());
}
2020-07-20 10:10:47 +02:00
$attribute = $this -> __fetchAttribute ( $id );
2019-08-14 14:17:58 +02:00
if ( empty ( $attribute )) {
throw new MethodNotAllowedException ( 'Invalid attribute' );
}
2020-07-20 10:10:47 +02:00
$this -> Attribute -> data = $attribute ;
2018-07-19 11:48:22 +02:00
if ( $this -> Attribute -> data [ 'Attribute' ][ 'deleted' ]) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
2020-07-20 10:10:47 +02:00
$this -> Attribute -> id = $attribute [ 'Attribute' ][ 'id' ];
if ( ! $this -> __canModifyEvent ( $attribute )) {
$message = __ ( 'You do not have permission to do that.' );
if ( $this -> _isRest ()) {
throw new ForbiddenException ( $message );
2018-07-19 11:48:22 +02:00
} else {
2020-07-20 10:10:47 +02:00
$this -> Flash -> error ( $message );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
2018-07-19 11:48:22 +02:00
}
}
2020-07-20 10:10:47 +02:00
$date = new DateTime ();
2018-07-19 11:48:22 +02:00
if ( ! $this -> _isRest ()) {
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $this -> Attribute -> data [ 'Attribute' ][ 'event_id' ]);
}
$eventId = $this -> Attribute -> data [ 'Attribute' ][ 'event_id' ];
if ( 'attachment' == $this -> Attribute -> data [ 'Attribute' ][ 'type' ] ||
'malware-sample' == $this -> Attribute -> data [ 'Attribute' ][ 'type' ]) {
$this -> set ( 'attachment' , true );
} else {
$this -> set ( 'attachment' , false );
}
if ( $this -> request -> is ( 'post' ) || $this -> request -> is ( 'put' )) {
if ( ! isset ( $this -> request -> data [ 'Attribute' ])) {
$this -> request -> data = array ( 'Attribute' => $this -> request -> data );
}
2020-05-07 13:34:00 +02:00
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'distribution' ]) && $this -> request -> data [ 'Attribute' ][ 'distribution' ] == 4 ) {
2020-08-06 11:52:53 +02:00
if ( ! $this -> __canUseSharingGroup ( $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ])) {
2020-08-05 22:39:17 +02:00
throw new ForbiddenException ( __ ( 'Invalid Sharing Group or not authorised.' ));
2020-04-20 09:49:12 +02:00
}
}
2018-07-19 11:48:22 +02:00
$existingAttribute = $this -> Attribute -> findByUuid ( $this -> Attribute -> data [ 'Attribute' ][ 'uuid' ]);
// check if the attribute has a timestamp already set (from a previous instance that is trying to edit via synchronisation)
// check which attribute is newer
if ( count ( $existingAttribute ) && ! $existingAttribute [ 'Attribute' ][ 'deleted' ]) {
$this -> request -> data [ 'Attribute' ][ 'id' ] = $existingAttribute [ 'Attribute' ][ 'id' ];
2021-07-08 15:38:22 +02:00
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $existingAttribute [ 'Attribute' ][ 'event_id' ];
2018-07-19 11:48:22 +02:00
$dateObj = new DateTime ();
2018-08-17 14:46:59 +02:00
$skipTimeCheck = false ;
2018-07-19 11:48:22 +02:00
if ( ! isset ( $this -> request -> data [ 'Attribute' ][ 'timestamp' ])) {
$this -> request -> data [ 'Attribute' ][ 'timestamp' ] = $dateObj -> getTimestamp ();
2018-08-17 14:46:59 +02:00
$skipTimeCheck = true ;
2018-07-19 11:48:22 +02:00
}
2018-08-17 14:46:59 +02:00
if ( $skipTimeCheck || $this -> request -> data [ 'Attribute' ][ 'timestamp' ] > $existingAttribute [ 'Attribute' ][ 'timestamp' ]) {
2019-06-13 09:16:34 +02:00
$recoverFields = array ( 'value' , 'to_ids' , 'distribution' , 'category' , 'type' , 'comment' , 'first_seen' , 'last_seen' );
2018-07-19 11:48:22 +02:00
foreach ( $recoverFields as $rF ) {
if ( ! isset ( $this -> request -> data [ 'Attribute' ][ $rF ])) {
$this -> request -> data [ 'Attribute' ][ $rF ] = $existingAttribute [ 'Attribute' ][ $rF ];
}
}
// carry on with adding this attribute - Don't forget! if orgc!=user org, create shadow attribute, not attribute!
} else {
// the old one is newer or the same, replace the request's attribute with the old one
throw new MethodNotAllowedException ( __ ( 'Attribute could not be saved: Attribute in the request not newer than the local copy.' ));
}
} else {
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
throw new NotFoundException ( __ ( 'Invalid attribute.' ));
} else {
$this -> Flash -> error ( __ ( 'Invalid attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
}
}
if ( $existingAttribute [ 'Attribute' ][ 'object_id' ]) {
2021-07-27 18:58:04 +02:00
$result = $this -> Attribute -> save ( $this -> request -> data , array ( 'fieldList' => Attribute :: EDITABLE_FIELDS ));
2020-02-27 11:07:17 +01:00
if ( $result ) {
2020-08-05 10:12:53 +02:00
$this -> Attribute -> AttributeTag -> handleAttributeTags ( $this -> Auth -> user (), $this -> request -> data [ 'Attribute' ], $attribute [ 'Event' ][ 'id' ], $capture = true );
2020-02-27 11:07:17 +01:00
}
2018-07-19 11:48:22 +02:00
$this -> Attribute -> Object -> updateTimestamp ( $existingAttribute [ 'Attribute' ][ 'object_id' ]);
} else {
$result = $this -> Attribute -> save ( $this -> request -> data );
2020-02-27 11:07:17 +01:00
if ( $result ) {
2020-08-05 10:12:53 +02:00
$this -> Attribute -> AttributeTag -> handleAttributeTags ( $this -> Auth -> user (), $this -> request -> data [ 'Attribute' ], $attribute [ 'Event' ][ 'id' ], $capture = true );
2020-02-27 11:07:17 +01:00
}
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
if ( $result ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Attribute updated.' )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Could not update attribute, reason: ' . json_encode ( $this -> Attribute -> validationErrors ))), 'status' => 200 , 'type' => 'json' ));
}
}
}
if ( $result ) {
$this -> Flash -> success ( __ ( 'The attribute has been saved' ));
// remove the published flag from the event
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> unpublishEvent ( $eventId );
2018-07-19 11:48:22 +02:00
if ( ! empty ( $this -> Attribute -> data [ 'Attribute' ][ 'object_id' ])) {
$object = $this -> Attribute -> Object -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Object.id' => $this -> Attribute -> data [ 'Attribute' ][ 'object_id' ])
));
if ( ! empty ( $object )) {
$object [ 'Object' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> Object -> save ( $object );
}
}
2019-11-26 10:12:07 +01:00
if ( $this -> _isRest ()) {
$saved_attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'id' => $this -> Attribute -> id ),
'recursive' => - 1 ,
'contain' => array ( 'AttributeTag' => array ( 'Tag' ))
));
if ( $this -> response -> type () === 'application/json' ) {
$type = 'json' ;
} else {
$type = 'xml' ;
}
App :: uses ( strtoupper ( $type ) . 'ConverterTool' , 'Tools' );
$tool = strtoupper ( $type ) . 'ConverterTool' ;
$converter = new $tool ();
$saved_attribute = $converter -> convertAttribute ( $saved_attribute , true );
return $this -> RestResponse -> viewData ( $saved_attribute , $type );
2018-07-19 11:48:22 +02:00
} else {
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $eventId ));
}
} else {
2019-02-26 14:09:41 +01:00
if ( $this -> _isRest ()) {
return $this -> RestResponse -> saveFailResponse ( 'Attributes' , 'edit' , false , $this -> Attribute -> validationErrors );
2018-07-19 11:48:22 +02:00
} else {
2019-02-26 14:09:41 +01:00
if ( ! CakeSession :: read ( 'Message.flash' )) {
$this -> Flash -> error ( __ ( 'The attribute could not be saved. Please, try again.' ));
} else {
$this -> request -> data = $this -> Attribute -> read ( null , $id );
}
2018-07-19 11:48:22 +02:00
}
}
} else {
$this -> request -> data = $this -> Attribute -> read ( null , $id );
}
$this -> set ( 'attribute' , $this -> request -> data );
if ( ! empty ( $this -> request -> data [ 'Attribute' ][ 'object_id' ])) {
$this -> set ( 'objectAttribute' , true );
} else {
$this -> set ( 'objectAttribute' , false );
}
// enabling / disabling the distribution field in the edit view based on whether user's org == orgc in the event
2020-08-05 19:52:54 +02:00
$this -> set ( 'event' , $attribute ); // Attribute contains 'Event' field
2018-07-19 11:48:22 +02:00
// needed for RBAC
// combobox for types
$types = array_keys ( $this -> Attribute -> typeDefinitions );
foreach ( $types as $key => $value ) {
if ( in_array ( $value , array ( 'malware-sample' , 'attachment' ))) {
unset ( $types [ $key ]);
}
}
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$this -> loadModel ( 'SharingGroup' );
$sgs = $this -> SharingGroup -> fetchAllAuthorised ( $this -> Auth -> user (), 'name' , 1 );
$this -> set ( 'sharingGroups' , $sgs );
$distributionLevels = $this -> Attribute -> distributionLevels ;
if ( empty ( $sgs )) {
unset ( $distributionLevels [ 4 ]);
}
$this -> set ( 'distributionLevels' , $distributionLevels );
foreach ( $this -> Attribute -> categoryDefinitions as $key => $value ) {
$info [ 'category' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
foreach ( $this -> Attribute -> typeDefinitions as $key => $value ) {
$info [ 'type' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
foreach ( $distributionLevels as $key => $value ) {
$info [ 'distribution' ][ $key ] = array ( 'key' => $value , 'desc' => $this -> Attribute -> distributionDescriptions [ $key ][ 'formdesc' ]);
}
$this -> set ( 'info' , $info );
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$categoryDefinitions = $this -> Attribute -> categoryDefinitions ;
$categories = array_keys ( $this -> Attribute -> categoryDefinitions );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
if ( ! empty ( $this -> request -> data [ 'Attribute' ][ 'object_id' ])) {
foreach ( $categoryDefinitions as $k => $v ) {
if ( ! in_array ( $this -> request -> data [ 'Attribute' ][ 'type' ], $v [ 'types' ])) {
unset ( $categoryDefinitions [ $k ]);
}
}
foreach ( $categories as $k => $v ) {
if ( ! isset ( $categoryDefinitions [ $k ])) {
unset ( $categories [ $k ]);
}
}
}
$this -> set ( 'categories' , $categories );
$this -> set ( 'categoryDefinitions' , $categoryDefinitions );
$this -> set ( 'action' , $this -> action );
$this -> loadModel ( 'Noticelist' );
$notice_list_triggers = $this -> Noticelist -> getTriggerData ();
$this -> set ( 'notice_list_triggers' , json_encode ( $notice_list_triggers , true ));
$this -> render ( 'add' );
}
// ajax edit - post a single edited field and this method will attempt to save it and return a json with the validation errors if they occur.
public function editField ( $id )
{
2020-07-20 10:10:47 +02:00
$attribute = $this -> __fetchAttribute ( $id );
2019-08-14 14:17:58 +02:00
if ( empty ( $attribute )) {
2020-07-20 10:10:47 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'fail' => false , 'errors' => 'Invalid attribute' )), 'status' => 200 , 'type' => 'json' ));
2019-08-14 14:17:58 +02:00
}
$this -> Attribute -> data = $attribute ;
2020-07-20 10:10:47 +02:00
$this -> Attribute -> id = $attribute [ 'Attribute' ][ 'id' ];
if ( ! $this -> __canModifyEvent ( $attribute )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'fail' => false , 'errors' => 'You do not have permission to do that' )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
if ( ! $this -> _isRest ()) {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $attribute [ 'Attribute' ][ 'event_id' ]);
2018-07-19 11:48:22 +02:00
}
2019-06-13 09:16:34 +02:00
$validFields = array ( 'value' , 'category' , 'type' , 'comment' , 'to_ids' , 'distribution' , 'first_seen' , 'last_seen' );
2018-07-19 11:48:22 +02:00
$changed = false ;
if ( empty ( $this -> request -> data [ 'Attribute' ])) {
$this -> request -> data = array ( 'Attribute' => $this -> request -> data );
if ( empty ( $this -> request -> data [ 'Attribute' ])) {
throw new MethodNotAllowedException ( __ ( 'Invalid input.' ));
}
}
foreach ( $this -> request -> data [ 'Attribute' ] as $changedKey => $changedField ) {
if ( ! in_array ( $changedKey , $validFields )) {
throw new MethodNotAllowedException ( __ ( 'Invalid field.' ));
}
if ( $attribute [ 'Attribute' ][ $changedKey ] == $changedField ) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'errors' => array ( 'value' => 'nochange' ))), 'status' => 200 , 'type' => 'json' ));
}
$attribute [ 'Attribute' ][ $changedKey ] = $changedField ;
$changed = true ;
}
if ( ! $changed ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'errors' => array ( 'value' => 'nochange' ))), 'status' => 200 , 'type' => 'json' ));
}
$date = new DateTime ();
$attribute [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
if ( $this -> Attribute -> save ( $attribute )) {
2020-07-20 10:10:47 +02:00
$this -> Attribute -> Event -> unpublishEvent ( $attribute [ 'Attribute' ][ 'event_id' ]);
2020-01-16 11:08:41 +01:00
if ( $attribute [ 'Attribute' ][ 'object_id' ] != 0 ) {
$this -> Attribute -> Object -> updateTimestamp ( $attribute [ 'Attribute' ][ 'object_id' ], $date -> getTimestamp ());
}
2018-07-19 11:48:22 +02:00
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Field updated.' , 'check_publish' => true )), 'status' => 200 , 'type' => 'json' ));
} else {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $this -> Attribute -> validationErrors )), 'status' => 200 , 'type' => 'json' ));
}
}
public function view ( $id )
{
2020-11-02 17:28:17 +01:00
if ( $this -> request -> is ( 'head' )) { // Just check if attribute exists
$attribute = $this -> Attribute -> fetchAttributesSimple ( $this -> Auth -> user (), [
'conditions' => $this -> __idToConditions ( $id ),
'fields' => [ 'Attribute.id' ],
]);
return new CakeResponse ([ 'status' => $attribute ? 200 : 404 ]);
}
2020-07-20 10:10:47 +02:00
$attribute = $this -> __fetchAttribute ( $id );
2019-03-13 13:58:37 +01:00
if ( empty ( $attribute )) {
2020-07-20 10:10:47 +02:00
throw new MethodNotAllowedException ( __ ( 'Invalid attribute' ));
2019-03-13 13:58:37 +01:00
}
2018-07-19 11:48:22 +02:00
if ( $this -> _isRest ()) {
if ( isset ( $attribute [ 'AttributeTag' ])) {
foreach ( $attribute [ 'AttributeTag' ] as $k => $tag ) {
$attribute [ 'Attribute' ][ 'Tag' ][ $k ] = $tag [ 'Tag' ];
}
}
unset ( $attribute [ 'Attribute' ][ 'value1' ]);
unset ( $attribute [ 'Attribute' ][ 'value2' ]);
$this -> set ( 'Attribute' , $attribute [ 'Attribute' ]);
$this -> set ( '_serialize' , array ( 'Attribute' ));
} else {
2019-03-13 13:58:37 +01:00
$this -> redirect ( '/events/view/' . $attribute [ 'Attribute' ][ 'event_id' ]);
}
}
2019-04-09 12:57:21 +02:00
public function viewPicture ( $id , $thumbnail = false )
2019-03-13 13:58:37 +01:00
{
2020-07-20 10:10:47 +02:00
$conditions = $this -> __idToConditions ( $id );
2019-10-12 09:35:47 +02:00
$conditions [ 'Attribute.type' ] = 'attachment' ;
$options = array (
'conditions' => $conditions ,
2019-03-18 09:59:54 +01:00
'includeAllTags' => false ,
'includeAttributeUuid' => true ,
2019-10-12 09:35:47 +02:00
'flatten' => true ,
2021-01-25 14:38:30 +01:00
'deleted' => [ 0 , 1 ]
2019-03-18 09:59:54 +01:00
);
2019-04-09 12:57:21 +02:00
if ( $this -> _isRest ()) {
2019-10-12 09:35:47 +02:00
$options [ 'withAttachments' ] = true ;
2019-04-09 12:57:21 +02:00
}
2019-10-12 09:35:47 +02:00
$attribute = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), $options );
2019-03-13 13:58:37 +01:00
if ( empty ( $attribute )) {
throw new MethodNotAllowedException ( 'Invalid attribute' );
}
$attribute = $attribute [ 0 ];
2019-10-12 09:35:47 +02:00
if ( ! $this -> Attribute -> isImage ( $attribute [ 'Attribute' ])) {
throw new NotFoundException ( " Attribute is not an image. " );
}
2019-03-13 13:58:37 +01:00
if ( $this -> _isRest ()) {
return $this -> RestResponse -> viewData ( $attribute [ 'Attribute' ][ 'data' ], $this -> response -> type ());
} else {
2019-04-09 12:57:21 +02:00
$width = isset ( $this -> request -> params [ 'named' ][ 'width' ]) ? $this -> request -> params [ 'named' ][ 'width' ] : 200 ;
$height = isset ( $this -> request -> params [ 'named' ][ 'height' ]) ? $this -> request -> params [ 'named' ][ 'height' ] : 200 ;
2019-10-12 09:35:47 +02:00
$imageData = $this -> Attribute -> getPictureData ( $attribute , $thumbnail , $width , $height );
$extension = pathinfo ( $attribute [ 'Attribute' ][ 'value' ], PATHINFO_EXTENSION );
return new CakeResponse ( array ( 'body' => $imageData , 'type' => strtolower ( $extension )));
2018-07-19 11:48:22 +02:00
}
}
public function delete ( $id , $hard = false )
{
2019-09-13 15:13:09 +02:00
if ( isset ( $this -> params [ 'named' ][ 'hard' ])) {
$hard = $this -> params [ 'named' ][ 'hard' ];
}
2019-09-13 15:18:39 +02:00
if ( isset ( $this -> request -> data [ 'hard' ])) {
$hard = $this -> request -> data [ 'hard' ];
}
2020-08-06 11:52:53 +02:00
$conditions = $this -> __idToConditions ( $id );
2018-07-19 11:48:22 +02:00
if ( ! $hard ) {
$conditions [ 'deleted' ] = 0 ;
}
$attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => $conditions ,
'recursive' => - 1 ,
'fields' => array ( 'id' , 'event_id' ),
));
if ( empty ( $attribute )) {
2019-08-14 14:17:58 +02:00
throw new NotFoundException ( 'Invalid attribute' );
2018-07-19 11:48:22 +02:00
}
2020-08-06 11:52:53 +02:00
$this -> set ( 'id' , $attribute [ 'Attribute' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'ajax' )) {
if ( $this -> request -> is ( 'post' )) {
2020-08-06 11:52:53 +02:00
if ( $this -> Attribute -> deleteAttribute ( $attribute [ 'Attribute' ][ 'id' ], $this -> Auth -> user (), $hard )) {
2018-07-19 11:48:22 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Attribute deleted.' )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Attribute was not deleted.' )), 'status' => 200 , 'type' => 'json' ));
}
} else {
$this -> set ( 'hard' , $hard );
$this -> set ( 'event_id' , $attribute [ 'Attribute' ][ 'event_id' ]);
$this -> render ( 'ajax/attributeConfirmationForm' );
}
} else {
2019-09-13 15:18:39 +02:00
if ( ! $this -> request -> is ( 'post' ) && ! $this -> request -> is ( 'delete' )) {
2019-09-13 15:13:09 +02:00
throw new MethodNotAllowedException ( __ ( 'This function is only accessible via POST requests.' ));
2018-07-19 11:48:22 +02:00
}
2020-08-06 11:52:53 +02:00
if ( $this -> Attribute -> deleteAttribute ( $attribute [ 'Attribute' ][ 'id' ], $this -> Auth -> user (), $hard )) {
2018-07-19 11:48:22 +02:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
$this -> set ( 'message' , 'Attribute deleted.' );
$this -> set ( '_serialize' , array ( 'message' ));
} else {
$this -> Flash -> success ( __ ( 'Attribute deleted' ));
$this -> redirect ( $this -> referer ());
}
} else {
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
throw new Exception ( __ ( 'Attribute was not deleted' ));
} else {
$this -> Flash -> error ( __ ( 'Attribute was not deleted' ));
$this -> redirect ( array ( 'action' => 'index' ));
}
$this -> Flash -> success ( __ ( 'Attribute deleted' ));
}
}
}
public function restore ( $id = null )
{
$attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'Attribute.id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'Attribute.id' , 'Attribute.event_id' ),
'contain' => array (
'Event' => array (
'fields' => array ( 'Event.orgc_id' )
)
)
));
if ( empty ( $attribute ) || ! $this -> userRole [ 'perm_site_admin' ] && $this -> Auth -> user ( 'org_id' ) != $attribute [ 'Event' ][ 'orgc_id' ]) {
if ( $this -> request -> is ( 'ajax' )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Attribute' )), 'type' => 'json' , 'status' => 200 ));
} else {
throw new MethodNotAllowedException ( __ ( 'Invalid Attribute' ));
}
}
if ( ! $this -> _isRest ()) {
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $attribute [ 'Attribute' ][ 'event_id' ]);
}
if ( $this -> request -> is ( 'ajax' )) {
if ( $this -> request -> is ( 'post' )) {
$result = $this -> Attribute -> restore ( $id , $this -> Auth -> user ());
if ( $result === true ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Attribute restored.' )), 'type' => 'json' , 'status' => 200 ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $result )), 'type' => 'json' , 'status' => 200 ));
}
} else {
$this -> set ( 'id' , $id );
$this -> set ( 'event_id' , $attribute [ 'Attribute' ][ 'event_id' ]);
$this -> render ( 'ajax/attributeRestorationForm' );
}
} else {
if ( ! $this -> request -> is ( 'post' ) && ! $this -> _isRest ()) {
throw new MethodNotAllowedException ();
}
if ( $this -> Attribute -> restore ( $id , $this -> Auth -> user ())) {
$this -> redirect ( array ( 'action' => 'view' , $id ));
} else {
throw new NotFoundException ( __ ( 'Could not restore the attribute' ));
}
}
}
public function deleteSelected ( $id = false , $hard = false )
{
if ( ! $this -> request -> is ( 'post' )) {
if ( $this -> request -> is ( 'get' )) {
return $this -> RestResponse -> describe ( 'Attributes' , 'deleteSelected' , false , $this -> response -> type ());
}
throw new MethodNotAllowedException ( __ ( 'This function is only accessible via POST requests.' ));
}
// get a json object with a list of attribute IDs to be deleted
// check each of them and return a json object with the successful deletes and the failed ones.
if ( $this -> _isRest ()) {
if ( empty ( $this -> request -> data [ 'Attribute' ])) {
$this -> request -> data [ 'Attribute' ] = $this -> request -> data ;
}
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'id' ])) {
$ids = $this -> request -> data [ 'Attribute' ][ 'id' ];
} else {
$ids = $this -> request -> data [ 'Attribute' ];
}
if ( empty ( $id ) && isset ( $this -> request -> data [ 'Attribute' ][ 'event_id' ]) && is_numeric ( $this -> request -> data [ 'Attribute' ][ 'event_id' ])) {
$id = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
}
} else {
$ids = json_decode ( $this -> request -> data [ 'Attribute' ][ 'ids_delete' ]);
}
if ( empty ( $id )) {
throw new MethodNotAllowedException ( __ ( 'No event ID set.' ));
}
if ( ! $this -> _isSiteAdmin ()) {
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc_id' , 'user_id' )
));
2020-08-06 11:52:53 +02:00
if ( ! $event ) {
throw new NotFoundException ( __ ( 'Invalid event' ));
}
2020-07-20 10:10:47 +02:00
if ( ! $this -> __canModifyEvent ( $event )) {
throw new ForbiddenException ( __ ( 'You do not have permission to do that.' ));
2018-07-19 11:48:22 +02:00
}
}
if ( empty ( $ids )) {
$ids = - 1 ;
}
$conditions = array ( 'id' => $ids , 'event_id' => $id );
if ( $ids == 'all' ) {
unset ( $conditions [ 'id' ]);
}
if ( $hard || ( $this -> _isRest () && empty ( $this -> request -> data [ 'Attribute' ][ 'allow_hard_delete' ]))) {
$conditions [ 'deleted' ] = 0 ;
}
// find all attributes from the ID list that also match the provided event ID.
$attributes = $this -> Attribute -> find ( 'all' , array (
'recursive' => - 1 ,
'conditions' => $conditions ,
'fields' => array ( 'id' , 'event_id' , 'deleted' )
));
if ( $ids == 'all' ) {
$ids = array ();
foreach ( $attributes as $attribute ) {
$ids [] = $attribute [ 'Attribute' ][ 'id' ];
}
}
if ( empty ( $attributes )) {
throw new NotFoundException ( __ ( 'No matching attributes found.' ));
}
$successes = array ();
foreach ( $attributes as $a ) {
if ( $hard ) {
2019-06-12 11:56:42 +02:00
if ( $this -> Attribute -> deleteAttribute ( $a [ 'Attribute' ][ 'id' ], $this -> Auth -> user (), true )) {
2018-07-19 11:48:22 +02:00
$successes [] = $a [ 'Attribute' ][ 'id' ];
}
} else {
2019-06-12 11:56:42 +02:00
if ( $this -> Attribute -> deleteAttribute ( $a [ 'Attribute' ][ 'id' ], $this -> Auth -> user (), $a [ 'Attribute' ][ 'deleted' ] == 1 ? true : false )) {
2018-07-19 11:48:22 +02:00
$successes [] = $a [ 'Attribute' ][ 'id' ];
}
}
}
$fails = array_diff ( $ids , $successes );
$this -> autoRender = false ;
if ( count ( $fails ) == 0 && count ( $successes ) > 0 ) {
$message = count ( $successes ) . ' attribute' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted.' ;
if ( $this -> _isRest ()) {
return $this -> RestResponse -> saveSuccessResponse ( 'Attributes' , 'deleteSelected' , $id , false , $message );
}
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $message )), 'status' => 200 , 'type' => 'json' ));
} else {
$message = count ( $successes ) . ' attribute' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted, but ' . count ( $fails ) . ' attribute' . ( count ( $fails ) != 1 ? 's' : '' ) . ' could not be deleted.' ;
if ( $this -> _isRest ()) {
return $this -> RestResponse -> saveFailResponse ( 'Attributes' , 'deleteSelected' , false , $message );
}
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $message )), 'status' => 200 , 'type' => 'json' ));
}
}
2020-07-28 10:15:31 +02:00
public function getMassEditForm ( $eventId )
2018-07-19 11:48:22 +02:00
{
2020-07-28 10:58:05 +02:00
if ( ! $this -> request -> is ( 'ajax' ) || ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( __ ( 'This method can only be accessed via AJAX and POST.' ));
2018-07-19 11:48:22 +02:00
}
2020-07-28 10:15:31 +02:00
if ( ! isset ( $eventId )) {
2020-07-27 12:10:53 +02:00
throw new MethodNotAllowedException ( __ ( 'No event ID provided.' ));
}
2020-07-28 10:15:31 +02:00
$event = $this -> Attribute -> Event -> fetchSimpleEvent ( $this -> Auth -> user (), $eventId , $params = array (
2020-07-27 12:10:53 +02:00
'fields' => array ( 'id' , 'orgc_id' , 'org_id' , 'user_id' , 'published' , 'timestamp' , 'info' , 'uuid' )
));
2020-07-28 10:15:31 +02:00
if ( empty ( $event )) {
throw new NotFoundException ( __ ( 'Invalid event' ));
}
2020-08-05 22:39:17 +02:00
if ( ! $this -> __canModifyEvent ( $event )) {
throw new ForbiddenException ( __ ( 'You are not authorized to edit this event.' ));
2020-07-27 12:10:53 +02:00
}
$selectedAttributeIds = $this -> Attribute -> jsonDecode ( $this -> request -> data [ 'selected_ids' ]);
2020-07-28 10:58:05 +02:00
if ( empty ( $selectedAttributeIds )) {
throw new MethodNotAllowedException ( __ ( 'No attributes selected' ));
}
2020-07-27 12:10:53 +02:00
2020-08-05 22:39:17 +02:00
$attributes = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), [
'conditions' => [ 'Attribute.id' => $selectedAttributeIds , 'Attribute.event_id' => $event [ 'Event' ][ 'id' ]],
'flatten' => true ,
]);
2020-07-27 12:10:53 +02:00
// tags to remove
2020-08-05 22:39:17 +02:00
$tags = $this -> Attribute -> AttributeTag -> getAttributesTags ( $attributes );
2020-07-27 12:10:53 +02:00
$tagItemsRemove = array ();
2021-05-04 14:49:18 +02:00
foreach ( $tags as $tag ) {
2020-07-27 12:10:53 +02:00
$tagName = $tag [ 'name' ];
$tagItemsRemove [] = array (
'name' => $tagName ,
'value' => $tag [ 'id' ],
'template' => array (
'name' => array (
'name' => $tagName ,
'label' => array (
'background' => isset ( $tag [ 'colour' ]) ? $tag [ 'colour' ] : '#ffffff'
)
),
)
);
}
unset ( $tags );
// clusters to remove
2021-05-04 14:49:18 +02:00
$clusters = $this -> Attribute -> AttributeTag -> getAttributesClusters ( $this -> Auth -> user (), $attributes );
2020-07-27 12:10:53 +02:00
$clusterItemsRemove = array ();
2021-05-04 14:49:18 +02:00
foreach ( $clusters as $cluster ) {
2020-07-27 12:10:53 +02:00
$name = $cluster [ 'value' ];
$optionName = $cluster [ 'value' ];
2020-08-05 22:39:17 +02:00
$synom = $cluster [ 'synonyms_string' ] !== '' ? " ( { $cluster [ 'synonyms_string' ] } ) " : '' ;
2020-07-27 12:10:53 +02:00
$optionName .= $synom ;
$temp = array (
'name' => $optionName ,
'value' => $cluster [ 'id' ],
'template' => array (
'name' => $name ,
'infoExtra' => $cluster [ 'description' ]
)
);
if ( $cluster [ 'synonyms_string' ] !== '' ) {
$temp [ 'infoContextual' ] = __ ( 'Synonyms: ' ) . $cluster [ 'synonyms_string' ];
2018-07-19 11:48:22 +02:00
}
2020-07-27 12:10:53 +02:00
$clusterItemsRemove [] = $temp ;
}
2020-07-28 10:58:05 +02:00
// clusters to add
$this -> GalaxyCluster = ClassRegistry :: init ( 'GalaxyCluster' );
2020-09-22 12:08:12 +02:00
$clusters = $this -> GalaxyCluster -> fetchGalaxyClusters ( $this -> Auth -> user (), array (
'fields' => array ( 'value' , 'id' ),
'conditions' => array ( 'published' => true )
2020-07-28 10:58:05 +02:00
));
$clusterItemsAdd = array ();
2021-05-04 14:49:18 +02:00
foreach ( $clusters as $cluster ) {
2020-07-28 10:58:05 +02:00
$clusterItemsAdd [] = array (
2020-09-22 12:08:12 +02:00
'name' => $cluster [ 'GalaxyCluster' ][ 'value' ],
'value' => $cluster [ 'GalaxyCluster' ][ 'id' ]
2020-07-28 10:58:05 +02:00
);
2020-07-27 12:10:53 +02:00
}
2020-07-28 10:58:05 +02:00
$tags = $this -> Attribute -> AttributeTag -> Tag -> fetchUsableTags ( $this -> Auth -> user ());
2020-07-27 12:10:53 +02:00
$tagItemsAdd = array ();
2020-08-05 22:39:17 +02:00
foreach ( $tags as $tag ) {
2020-07-28 10:58:05 +02:00
$tagName = $tag [ 'Tag' ][ 'name' ];
if ( isset ( $clusters [ $tagName ])) {
continue ; // skip galaxy cluster tags
}
2020-07-27 12:10:53 +02:00
$tagItemsAdd [] = array (
'name' => $tagName ,
2020-07-28 10:58:05 +02:00
'value' => $tag [ 'Tag' ][ 'id' ],
2020-07-27 12:10:53 +02:00
'template' => array (
'name' => array (
'name' => $tagName ,
'label' => array (
2020-07-28 10:58:05 +02:00
'background' => isset ( $tag [ 'Tag' ][ 'colour' ]) ? $tag [ 'Tag' ][ 'colour' ] : '#ffffff'
2020-07-27 12:10:53 +02:00
)
),
)
);
}
$this -> layout = 'ajax' ;
2020-07-28 10:15:31 +02:00
$this -> set ( 'id' , $eventId );
2020-07-27 12:10:53 +02:00
$this -> set ( 'selectedAttributeIds' , $selectedAttributeIds );
$this -> set ( 'sgs' , $this -> Attribute -> SharingGroup -> fetchAllAuthorised ( $this -> Auth -> user (), 'name' , true ));
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
$this -> set ( 'distributionDescriptions' , $this -> Attribute -> distributionDescriptions );
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'tagItemsRemove' , $tagItemsRemove );
$this -> set ( 'tagItemsAdd' , $tagItemsAdd );
$this -> set ( 'clusterItemsAdd' , $clusterItemsAdd );
$this -> set ( 'clusterItemsRemove' , $clusterItemsRemove );
$this -> set ( 'options' , array ( // set chosen (select picker) options
'multiple' => - 1 ,
2021-05-04 14:29:54 +02:00
'autofocus' => false ,
2020-07-27 12:10:53 +02:00
'disabledSubmitButton' => true ,
'flag_redraw_chosen' => true ,
'select_options' => array (
'additionalData' => array (
2020-07-28 10:15:31 +02:00
'event_id' => $eventId ,
2018-07-19 11:48:22 +02:00
),
2020-07-27 12:10:53 +02:00
),
));
$this -> render ( 'ajax/attributeEditMassForm' );
}
public function editSelected ( $id )
{
2020-08-05 22:39:17 +02:00
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( __ ( 'This method can only be accessed via POST.' ));
}
2018-07-19 11:48:22 +02:00
2020-08-05 22:39:17 +02:00
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc_id' , 'org_id' , 'user_id' , 'published' , 'timestamp' , 'info' , 'uuid' )
));
if ( ! $event ) {
throw new NotFoundException ( __ ( 'Invalid event' ));
}
if ( ! $this -> __canModifyEvent ( $event )) {
throw new ForbiddenException ( __ ( 'You are not authorized to edit this event.' ));
}
$attribute_ids = $this -> Attribute -> jsonDecode ( $this -> request -> data [ 'Attribute' ][ 'attribute_ids' ]);
$attributes = $this -> Attribute -> find ( 'all' , array (
'conditions' => array (
'id' => $attribute_ids ,
'event_id' => $id ,
),
'recursive' => - 1 ,
));
2018-07-19 11:48:22 +02:00
2020-08-05 22:39:17 +02:00
$tags_ids_remove = json_decode ( $this -> request -> data [ 'Attribute' ][ 'tags_ids_remove' ]);
$tags_ids_add = json_decode ( $this -> request -> data [ 'Attribute' ][ 'tags_ids_add' ]);
$clusters_ids_remove = json_decode ( $this -> request -> data [ 'Attribute' ][ 'clusters_ids_remove' ]);
$clusters_ids_add = json_decode ( $this -> request -> data [ 'Attribute' ][ 'clusters_ids_add' ]);
$changeInTagOrCluster = ( $tags_ids_remove !== null && count ( $tags_ids_remove ) > 0 )
|| ( $tags_ids_add === null || count ( $tags_ids_add ) > 0 )
|| ( $clusters_ids_remove === null || count ( $clusters_ids_remove ) > 0 )
|| ( $clusters_ids_add === null || count ( $clusters_ids_add ) > 0 );
2019-01-16 15:59:49 +01:00
2020-08-05 22:39:17 +02:00
$changeInAttribute = ( $this -> request -> data [ 'Attribute' ][ 'to_ids' ] != 2 ) || ( $this -> request -> data [ 'Attribute' ][ 'distribution' ] != 6 ) || ( $this -> request -> data [ 'Attribute' ][ 'comment' ] != null );
2019-01-16 15:59:49 +01:00
2020-08-05 22:39:17 +02:00
if ( ! $changeInAttribute && ! $changeInTagOrCluster ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true )), 'status' => 200 , 'type' => 'json' ));
}
if ( $this -> request -> data [ 'Attribute' ][ 'to_ids' ] != 2 ) {
foreach ( $attributes as $key => $attribute ) {
$attributes [ $key ][ 'Attribute' ][ 'to_ids' ] = $this -> request -> data [ 'Attribute' ][ 'to_ids' ] == 0 ? false : true ;
2018-07-19 11:48:22 +02:00
}
2020-08-05 22:39:17 +02:00
}
2018-07-19 11:48:22 +02:00
2020-08-05 22:39:17 +02:00
if ( $this -> request -> data [ 'Attribute' ][ 'distribution' ] != 6 ) {
foreach ( $attributes as $key => $attribute ) {
$attributes [ $key ][ 'Attribute' ][ 'distribution' ] = $this -> request -> data [ 'Attribute' ][ 'distribution' ];
2018-07-19 11:48:22 +02:00
}
2020-08-05 22:39:17 +02:00
if ( $this -> request -> data [ 'Attribute' ][ 'distribution' ] == 4 ) {
$sharingGroupId = $this -> request -> data [ 'Attribute' ][ 'sharing_group_id' ];
2020-08-06 11:52:53 +02:00
if ( ! $this -> __canUseSharingGroup ( $sharingGroupId )) {
2020-08-05 22:39:17 +02:00
throw new ForbiddenException ( __ ( 'Invalid Sharing Group or not authorised.' ));
}
2018-07-19 11:48:22 +02:00
foreach ( $attributes as $key => $attribute ) {
2020-08-05 22:39:17 +02:00
$attributes [ $key ][ 'Attribute' ][ 'sharing_group_id' ] = $sharingGroupId ;
2018-07-19 11:48:22 +02:00
}
2020-08-05 22:39:17 +02:00
} else {
2018-07-19 11:48:22 +02:00
foreach ( $attributes as $key => $attribute ) {
2020-08-05 22:39:17 +02:00
$attributes [ $key ][ 'Attribute' ][ 'sharing_group_id' ] = 0 ;
2018-07-19 11:48:22 +02:00
}
}
2020-08-05 22:39:17 +02:00
}
2018-07-19 11:48:22 +02:00
2020-08-05 22:39:17 +02:00
if ( $this -> request -> data [ 'Attribute' ][ 'comment' ] != null ) {
2018-07-19 11:48:22 +02:00
foreach ( $attributes as $key => $attribute ) {
2020-08-05 22:39:17 +02:00
$attributes [ $key ][ 'Attribute' ][ 'comment' ] = $this -> request -> data [ 'Attribute' ][ 'comment' ];
2018-07-19 11:48:22 +02:00
}
2020-08-05 22:39:17 +02:00
}
2019-01-16 15:59:49 +01:00
2020-08-05 22:39:17 +02:00
$date = new DateTime ();
$timestamp = $date -> getTimestamp ();
foreach ( $attributes as $key => $attribute ) {
$attributes [ $key ][ 'Attribute' ][ 'timestamp' ] = $timestamp ;
}
if ( $changeInAttribute ) {
if ( $this -> request -> data [ 'Attribute' ][ 'is_proposal' ]) { // create ShadowAttributes instead
$shadowAttributes = array ();
foreach ( $attributes as $attribute ) {
$shadowAttribute [ 'ShadowAttribute' ] = $attribute [ 'Attribute' ];
unset ( $shadowAttribute [ 'ShadowAttribute' ][ 'id' ]);
$shadowAttribute [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$shadowAttribute [ 'ShadowAttribute' ][ 'org_id' ] = $this -> Auth -> user ( 'org_id' );
$shadowAttribute [ 'ShadowAttribute' ][ 'event_uuid' ] = $event [ 'Event' ][ 'uuid' ];
$shadowAttribute [ 'ShadowAttribute' ][ 'event_org_id' ] = $event [ 'Event' ][ 'org_id' ];
$shadowAttribute [ 'ShadowAttribute' ][ 'old_id' ] = $attribute [ 'Attribute' ][ 'id' ];
$shadowAttributes [] = $shadowAttribute ;
2019-01-16 15:59:49 +01:00
}
2020-08-05 22:39:17 +02:00
$saveSuccess = $this -> Attribute -> ShadowAttribute -> saveMany ( $shadowAttributes );
} else {
$saveSuccess = $this -> Attribute -> saveMany ( $attributes );
}
if ( $saveSuccess ) {
if ( ! $this -> _isRest ()) {
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
2019-01-16 15:59:49 +01:00
}
2020-08-05 22:39:17 +02:00
$event [ 'Event' ][ 'timestamp' ] = $timestamp ;
$event [ 'Event' ][ 'published' ] = 0 ;
$this -> Attribute -> Event -> save ( $event , array ( 'fieldList' => array ( 'published' , 'timestamp' , 'id' )));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'validationErrors' => $this -> Attribute -> validationErrors )), 'status' => 200 , 'type' => 'json' ));
2019-01-16 15:59:49 +01:00
}
2020-08-05 22:39:17 +02:00
}
2019-01-16 15:59:49 +01:00
2020-08-05 22:39:17 +02:00
// apply changes in tag/cluster
foreach ( $attributes as $key => $attribute ) {
foreach ( $tags_ids_remove as $tag_id ) {
$this -> removeTag ( $attributes [ $key ][ 'Attribute' ][ 'id' ], $tag_id );
2019-01-16 15:59:49 +01:00
}
2020-08-05 22:39:17 +02:00
foreach ( $tags_ids_add as $tag_id ) {
$this -> addTag ( $attributes [ $key ][ 'Attribute' ][ 'id' ], $tag_id );
2019-01-16 15:59:49 +01:00
}
2020-08-05 22:39:17 +02:00
$this -> Galaxy = ClassRegistry :: init ( 'Galaxy' );
foreach ( $clusters_ids_remove as $cluster_id ) {
$this -> Galaxy -> detachCluster ( $this -> Auth -> user (), 'attribute' , $attributes [ $key ][ 'Attribute' ][ 'id' ], $cluster_id );
}
foreach ( $clusters_ids_add as $cluster_id ) {
$this -> Galaxy -> attachCluster ( $this -> Auth -> user (), 'attribute' , $attributes [ $key ][ 'Attribute' ][ 'id' ], $cluster_id );
2019-01-16 15:59:49 +01:00
}
2018-07-19 11:48:22 +02:00
}
2020-08-05 22:39:17 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
2018-10-04 22:24:35 +02:00
public function search ( $continue = false )
2018-07-19 11:48:22 +02:00
{
2019-01-16 12:58:27 +01:00
if ( $this -> request -> is ( 'post' ) || ! empty ( $this -> request -> params [ 'named' ][ 'tags' ])) {
2018-11-23 14:11:33 +01:00
if ( isset ( $this -> request -> data [ 'Attribute' ])) {
$this -> request -> data = $this -> request -> data [ 'Attribute' ];
}
2020-01-23 14:14:14 +01:00
$checkForEmpty = array ( 'value' , 'tags' , 'uuid' , 'org' , 'type' , 'category' , 'first_seen' , 'last_seen' );
2018-11-23 14:11:33 +01:00
foreach ( $checkForEmpty as $field ) {
if ( empty ( $this -> request -> data [ $field ]) || $this -> request -> data [ $field ] === 'ALL' ) {
unset ( $this -> request -> data [ $field ]);
}
}
if ( empty ( $this -> request -> data [ 'to_ids' ])) {
unset ( $this -> request -> data [ 'to_ids' ]);
$this -> request -> data [ 'ignore' ] = 1 ;
}
2019-06-13 09:16:34 +02:00
$paramArray = array ( 'value' , 'type' , 'category' , 'org' , 'tags' , 'from' , 'to' , 'last' , 'eventid' , 'withAttachments' , 'uuid' , 'publish_timestamp' , 'timestamp' , 'enforceWarninglist' , 'to_ids' , 'deleted' , 'includeEventUuid' , 'event_timestamp' , 'threat_level_id' , 'includeEventTags' , 'first_seen' , 'last_seen' );
2018-11-23 14:11:33 +01:00
$filterData = array (
'request' => $this -> request ,
2021-09-29 13:49:24 +02:00
'named_params' => $this -> request -> params [ 'named' ],
2018-11-23 14:11:33 +01:00
'paramArray' => $paramArray ,
'additional_delimiters' => PHP_EOL
);
$exception = false ;
$filters = $this -> _harvestParameters ( $filterData , $exception );
2020-04-01 23:14:29 +02:00
if ( ! empty ( $filters [ 'uuid' ])) {
if ( ! is_array ( $filters [ 'uuid' ])) {
$filters [ 'uuid' ] = array ( $filters [ 'uuid' ]);
}
$uuid = array ();
$ids = array ();
foreach ( $filters [ 'uuid' ] as $k => $filter ) {
if ( $filter [ 0 ] === '!' ) {
$filter = substr ( $filter , 1 );
}
if ( Validation :: uuid ( $filter )) {
$uuid [] = $filters [ 'uuid' ][ $k ];
} else {
$ids [] = $filters [ 'uuid' ][ $k ];
}
}
if ( empty ( $uuid )) {
unset ( $filters [ 'uuid' ]);
} else {
$filters [ 'uuid' ] = $uuid ;
}
if ( ! empty ( $ids )) {
$filters [ 'eventid' ] = $ids ;
}
}
2018-11-23 14:11:33 +01:00
unset ( $filterData );
if ( $filters === false ) {
return $exception ;
}
$this -> Session -> write ( 'search_attributes_filters' , json_encode ( $filters ));
} elseif ( $continue === 'results' ) {
$filters = $this -> Session -> read ( 'search_attributes_filters' );
if ( empty ( $filters )) {
$filters = array ();
} else {
$filters = json_decode ( $filters , true );
}
} else {
2020-08-17 13:32:00 +02:00
$types = $this -> _arrayToValuesIndexArray ( array_keys ( $this -> Attribute -> typeDefinitions ));
ksort ( $types );
$this -> set ( 'types' , array_merge ([ 'ALL' => 'ALL' ], $types ));
2018-11-23 14:11:33 +01:00
// combobox for categories
2020-08-17 13:32:00 +02:00
$categories = array_merge ([ 'ALL' => 'ALL' ], $this -> _arrayToValuesIndexArray ( array_keys ( $this -> Attribute -> categoryDefinitions )));
2018-11-23 14:11:33 +01:00
$this -> set ( 'categories' , $categories );
2020-08-17 13:32:00 +02:00
$categoryDefinition = $this -> Attribute -> categoryDefinitions ;
$categoryDefinition [ 'ALL' ] = [ 'types' => array_keys ( $this -> Attribute -> typeDefinitions ), 'formdesc' => '' ];
foreach ( $categoryDefinition as & $def ) {
$def [ 'types' ] = array_merge ([ 'ALL' ], $def [ 'types' ]);
}
$this -> set ( 'categoryDefinitions' , $categoryDefinition );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
2018-11-23 14:11:33 +01:00
$this -> Session -> write ( 'search_attributes_filters' , null );
}
if ( isset ( $filters )) {
$params = $this -> Attribute -> restSearch ( $this -> Auth -> user (), 'json' , $filters , true );
if ( ! isset ( $params [ 'conditions' ][ 'Attribute.deleted' ])) {
$params [ 'conditions' ][ 'Attribute.deleted' ] = 0 ;
}
$this -> paginate = $params ;
if ( empty ( $this -> paginate [ 'limit' ])) {
$this -> paginate [ 'limit' ] = 60 ;
}
if ( empty ( $this -> paginate [ 'page' ])) {
$this -> paginate [ 'page' ] = 1 ;
}
$this -> paginate [ 'recursive' ] = - 1 ;
$this -> paginate [ 'contain' ] = array (
'Event' => array (
2018-11-12 11:59:56 +01:00
'fields' => array ( 'Event.id' , 'Event.orgc_id' , 'Event.org_id' , 'Event.info' , 'Event.user_id' , 'Event.date' ),
2018-10-04 22:24:35 +02:00
),
2021-11-06 11:44:13 +01:00
'AttributeTag' ,
2018-11-23 14:11:33 +01:00
'Object' => array (
2018-10-04 22:24:35 +02:00
'fields' => array ( 'Object.id' , 'Object.distribution' , 'Object.sharing_group_id' )
2020-07-27 22:00:31 +02:00
),
'SharingGroup' => [ 'fields' => [ 'SharingGroup.name' ]],
2018-11-23 14:11:33 +01:00
);
$attributes = $this -> paginate ();
2021-11-06 11:44:13 +01:00
$this -> Attribute -> attachTagsToAttributes ( $attributes , [ 'includeAllTags' => true ]);
2020-11-22 19:14:25 +01:00
2020-12-10 13:45:56 +01:00
$orgTable = $this -> Attribute -> Event -> Orgc -> find ( 'all' , [
'fields' => [ 'Orgc.id' , 'Orgc.name' , 'Orgc.uuid' ],
]);
$orgTable = Hash :: combine ( $orgTable , '{n}.Orgc.id' , '{n}.Orgc' );
2020-11-22 19:14:25 +01:00
foreach ( $attributes as & $attribute ) {
if ( isset ( $orgTable [ $attribute [ 'Event' ][ 'orgc_id' ]])) {
2020-12-10 13:45:56 +01:00
$attribute [ 'Event' ][ 'Orgc' ] = $orgTable [ $attribute [ 'Event' ][ 'orgc_id' ]];
2020-11-22 19:14:25 +01:00
}
if ( isset ( $orgTable [ $attribute [ 'Event' ][ 'org_id' ]])) {
2020-12-10 13:45:56 +01:00
$attribute [ 'Event' ][ 'Org' ] = $orgTable [ $attribute [ 'Event' ][ 'org_id' ]];
2020-11-22 19:14:25 +01:00
}
}
if ( $this -> _isRest ()) {
2018-11-23 14:11:33 +01:00
return $this -> RestResponse -> viewData ( $attributes , $this -> response -> type ());
}
2020-11-22 19:14:25 +01:00
list ( $attributes , $sightingsData ) = $this -> __searchUI ( $attributes );
$this -> set ( 'sightingsData' , $sightingsData );
2019-01-16 12:58:27 +01:00
if ( isset ( $filters [ 'tags' ]) && ! empty ( $filters [ 'tags' ])) {
// if the tag is passed by ID - show its name in the view
$this -> loadModel ( 'Tag' );
2019-01-16 14:13:00 +01:00
if ( ! is_array ( $filters [ 'tags' ])) {
$filters [ 'tags' ] = array ( $filters [ 'tags' ]);
}
2019-01-16 12:58:27 +01:00
foreach ( $filters [ 'tags' ] as $k => & $v ) {
if ( ! is_numeric ( $v ))
continue ;
$tag = $this -> Tag -> find ( 'first' , [
'conditions' => [ 'Tag.id' => $v ],
'fields' => [ 'name' ],
'recursive' => - 1
]);
if ( ! empty ( $tag )) {
$v = $tag [ 'Tag' ][ 'name' ];
}
}
}
2020-12-10 13:45:56 +01:00
$this -> set ( 'orgTable' , array_column ( $orgTable , 'name' , 'id' ));
2018-11-23 14:11:33 +01:00
$this -> set ( 'filters' , $filters );
$this -> set ( 'attributes' , $attributes );
$this -> set ( 'isSearch' , 1 );
2020-08-17 13:32:00 +02:00
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'shortDist' , $this -> Attribute -> shortDist );
2021-07-29 15:59:26 +02:00
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
2018-11-23 14:11:33 +01:00
$this -> render ( 'index' );
}
2018-10-04 22:24:35 +02:00
if ( isset ( $attributeTags )) {
$this -> set ( 'attributeTags' , $attributeTags );
2018-07-19 11:48:22 +02:00
}
}
2021-11-06 12:38:08 +01:00
private function __searchUI ( array $attributes )
2018-11-23 14:11:33 +01:00
{
2020-11-23 10:52:09 +01:00
if ( empty ( $attributes )) {
return [[], []];
}
2018-11-23 14:11:33 +01:00
$this -> Feed = ClassRegistry :: init ( 'Feed' );
2019-10-20 14:03:35 +02:00
2018-11-23 14:11:33 +01:00
$this -> loadModel ( 'Sighting' );
2020-10-08 19:27:49 +02:00
$this -> loadModel ( 'AttachmentScan' );
2019-10-20 14:03:35 +02:00
$user = $this -> Auth -> user ();
2020-11-23 10:52:09 +01:00
$attributeIds = [];
2021-11-06 12:38:08 +01:00
$galaxyTags = [];
foreach ( $attributes as & $attribute ) {
$attributeIds [] = $attribute [ 'Attribute' ][ 'id' ];
2019-10-12 09:52:59 +02:00
if ( $this -> Attribute -> isImage ( $attribute [ 'Attribute' ])) {
if ( extension_loaded ( 'gd' )) {
// if extension is loaded, the data is not passed to the view because it is asynchronously fetched
$attribute [ 'Attribute' ][ 'image' ] = true ; // tell the view that it is an image despite not having the actual data
} else {
$attribute [ 'Attribute' ][ 'image' ] = $this -> Attribute -> base64EncodeAttachment ( $attribute [ 'Attribute' ]);
}
}
2020-10-08 19:27:49 +02:00
if ( $attribute [ 'Attribute' ][ 'type' ] === 'attachment' && $this -> AttachmentScan -> isEnabled ()) {
$infected = $this -> AttachmentScan -> isInfected ( AttachmentScan :: TYPE_ATTRIBUTE , $attribute [ 'Attribute' ][ 'id' ]);
2021-11-06 12:38:08 +01:00
$attribute [ 'Attribute' ][ 'infected' ] = $infected ;
2020-10-08 19:27:49 +02:00
}
2019-10-12 09:52:59 +02:00
2020-07-27 22:00:31 +02:00
if ( $attribute [ 'Attribute' ][ 'distribution' ] == 4 ) {
2021-11-06 12:38:08 +01:00
$attribute [ 'Attribute' ][ 'SharingGroup' ] = $attribute [ 'SharingGroup' ];
2020-07-27 22:00:31 +02:00
}
2021-11-06 12:38:08 +01:00
$attribute [ 'Attribute' ][ 'AttributeTag' ] = $attribute [ 'AttributeTag' ];
foreach ( $attribute [ 'Attribute' ][ 'AttributeTag' ] as $at ) {
if ( substr ( $at [ 'Tag' ][ 'name' ], 0 , 12 ) === 'misp-galaxy:' ) {
$galaxyTags [] = $at [ 'Tag' ][ 'name' ];
}
}
unset ( $attribute [ 'AttributeTag' ]);
2020-11-23 09:27:03 +01:00
}
2021-11-06 12:38:08 +01:00
unset ( $attribute );
// Fetch galaxy clusters in one query
$this -> loadModel ( 'GalaxyCluster' );
$clusters = $this -> GalaxyCluster -> getClusters ( $galaxyTags , $user , true , false );
$clusters = array_column ( array_column ( $clusters , 'GalaxyCluster' ), null , 'tag_id' );
2020-11-23 09:27:03 +01:00
2020-11-23 10:52:09 +01:00
// Fetch correlations in one query
2021-07-20 12:34:16 +02:00
$correlations = $this -> Attribute -> Event -> getRelatedAttributes ( $user , $attributeIds , false , 'attribute' );
2020-11-23 10:52:09 +01:00
2020-11-23 09:27:03 +01:00
// `attachFeedCorrelations` method expects different attribute format, so we need to transform that, then process
// and then take information back to original attribute structure.
$fakeEventArray = [];
$attributesWithFeedCorrelations = $this -> Feed -> attachFeedCorrelations ( array_column ( $attributes , 'Attribute' ), $user , $fakeEventArray );
2020-11-23 10:52:09 +01:00
foreach ( $attributes as $k => $attribute ) {
2021-11-06 12:38:08 +01:00
// Assign galaxies
$galaxies = [];
foreach ( $attribute [ 'Attribute' ][ 'AttributeTag' ] as $k2 => $attributeTag ) {
if ( ! isset ( $clusters [ $attributeTag [ 'Tag' ][ 'id' ]])) {
continue ;
}
$cluster = $clusters [ $attributeTag [ 'Tag' ][ 'id' ]];
$galaxyId = $cluster [ 'Galaxy' ][ 'id' ];
$cluster [ 'local' ] = isset ( $attributeTag [ 'local' ]) ? $attributeTag [ 'local' ] : false ;
if ( isset ( $attribute [ 'Attribute' ][ 'Galaxy' ][ $galaxyId ])) {
unset ( $cluster [ 'Galaxy' ]);
$galaxies [ $galaxyId ][ 'GalaxyCluster' ][] = $cluster ;
} else {
$galaxies [ $galaxyId ] = $cluster [ 'Galaxy' ];
unset ( $cluster [ 'Galaxy' ]);
$galaxies [ $galaxyId ][ 'GalaxyCluster' ] = [ $cluster ];
}
unset ( $attributes [ $k ][ 'Attribute' ][ 'AttributeTag' ][ $k2 ]); // remove galaxy tag
}
$attributes [ $k ][ 'Attribute' ][ 'Galaxy' ] = array_values ( $galaxies );
2020-11-23 10:52:09 +01:00
if ( isset ( $attributesWithFeedCorrelations [ $k ][ 'Feed' ])) {
$attributes [ $k ][ 'Attribute' ][ 'Feed' ] = $attributesWithFeedCorrelations [ $k ][ 'Feed' ];
}
if ( isset ( $correlations [ $attribute [ 'Attribute' ][ 'id' ]])) {
$attributes [ $k ][ 'Attribute' ][ 'RelatedAttribute' ] = $correlations [ $attribute [ 'Attribute' ][ 'id' ]];
2018-11-23 14:11:33 +01:00
}
}
2020-11-11 09:00:50 +01:00
$sightingsData = $this -> Sighting -> attributesStatistics ( $attributes , $user );
2018-11-23 14:11:33 +01:00
return array ( $attributes , $sightingsData );
}
2018-11-12 11:59:56 +01:00
2018-07-19 11:48:22 +02:00
// If the checkbox for the alternate search is ticked, then this method is called to return the data to be represented
// This alternate view will show a list of events with matching search results and the percentage of those matched attributes being marked as to_ids
// events are sorted based on relevance (as in the percentage of matches being flagged as indicators for IDS)
public function searchAlternate ( $data )
{
$attributes = $this -> Attribute -> fetchAttributes (
$this -> Auth -> user (),
array (
'conditions' => array (
'AND' => $data
),
'contain' => array ( 'Event' => array ( 'Orgc' => array ( 'fields' => array ( 'Orgc.name' )))),
'fields' => array (
'Attribute.id' , 'Attribute.event_id' , 'Attribute.type' , 'Attribute.category' , 'Attribute.to_ids' , 'Attribute.value' , 'Attribute.distribution' ,
'Event.id' , 'Event.org_id' , 'Event.orgc_id' , 'Event.info' , 'Event.distribution' , 'Event.attribute_count' , 'Event.date' ,
)
)
);
$events = array ();
foreach ( $attributes as $attribute ) {
if ( isset ( $events [ $attribute [ 'Event' ][ 'id' ]])) {
if ( $attribute [ 'Attribute' ][ 'to_ids' ]) {
$events [ $attribute [ 'Event' ][ 'id' ]][ 'to_ids' ] ++ ;
} else {
$events [ $attribute [ 'Event' ][ 'id' ]][ 'no_ids' ] ++ ;
}
} else {
$events [ $attribute [ 'Event' ][ 'id' ]][ 'Event' ] = $attribute [ 'Event' ];
$events [ $attribute [ 'Event' ][ 'id' ]][ 'to_ids' ] = 0 ;
$events [ $attribute [ 'Event' ][ 'id' ]][ 'no_ids' ] = 0 ;
if ( $attribute [ 'Attribute' ][ 'to_ids' ]) {
$events [ $attribute [ 'Event' ][ 'id' ]][ 'to_ids' ] ++ ;
} else {
$events [ $attribute [ 'Event' ][ 'id' ]][ 'no_ids' ] ++ ;
}
}
}
foreach ( $events as $key => $event ) {
$events [ $key ][ 'relevance' ] = 100 * $event [ 'to_ids' ] / ( $event [ 'no_ids' ] + $event [ 'to_ids' ]);
}
if ( ! empty ( $events )) {
$events = $this -> __subval_sort ( $events , 'relevance' );
}
return $events ;
}
// Sort the array of arrays based on a value of a sub-array
private function __subval_sort ( $a , $subkey )
{
foreach ( $a as $k => $v ) {
$b [ $k ] = strtolower ( $v [ $subkey ]);
}
arsort ( $b );
foreach ( $b as $key => $val ) {
$c [] = $a [ $key ];
}
return $c ;
}
public function checkComposites ()
{
if ( ! self :: _isAdmin ()) {
throw new NotFoundException ();
}
$this -> set ( 'fails' , $this -> Attribute -> checkComposites ());
}
public function downloadAttachment ( $key = 'download' , $id )
{
if ( $key != null && $key != 'download' ) {
2021-09-26 12:23:23 +02:00
$user = $this -> _checkAuthUser ( $key );
2018-07-19 11:48:22 +02:00
} else {
if ( ! $this -> Auth -> user ()) {
throw new UnauthorizedException ( __ ( 'You are not authorized. Please send the Authorization header with your auth key along with an Accept header for application/xml.' ));
}
2021-09-26 12:23:23 +02:00
$user = $this -> _checkAuthUser ( $this -> Auth -> user ( 'authkey' ));
2018-07-19 11:48:22 +02:00
}
// if the user is authorised to use the api key then user will be populated with the user's account
// in addition we also set a flag indicating whether the user is a site admin or not.
if ( ! $user ) {
throw new UnauthorizedException ( __ ( 'This authentication key is not authorized to be used for exports. Contact your administrator.' ));
}
2020-07-20 10:10:47 +02:00
$conditions = $this -> __idToConditions ( $id );
2020-06-29 14:10:23 +02:00
$conditions [ 'Attribute.type' ] = array ( 'attachment' , 'malware-sample' );
$attributes = $this -> Attribute -> fetchAttributes ( $user , array ( 'conditions' => $conditions , 'flatten' => true ));
2018-07-19 11:48:22 +02:00
if ( empty ( $attributes )) {
2020-06-29 14:10:23 +02:00
throw new UnauthorizedException ( __ ( 'Attribute does not exists or you do not have the permission to download this attribute.' ));
2018-07-19 11:48:22 +02:00
}
2020-06-29 14:10:23 +02:00
$this -> __downloadAttachment ( $attributes [ 0 ][ 'Attribute' ]);
2018-07-19 11:48:22 +02:00
}
2020-06-29 21:09:47 +02:00
// returns an XML with attributes that belong to an event. The type of attributes to be returned can be restricted by type using the 3rd parameter.
// Similar to the restSearch, this parameter can be chained with '&&' and negations are accepted too. For example filename&&!filename|md5 would return all filenames that don't have an md5
// The usage of returnAttributes is the following: [MISP-url]/attributes/returnAttributes/<API-key>/<event_id>/<type>/<signature flag>
// The signature flag is off by default, enabling it will only return attributes that have the to_ids flag set to true.
public function returnAttributes ()
2018-07-19 11:48:22 +02:00
{
2020-06-29 21:09:47 +02:00
//$key='download', $id, $type = null, $sigOnly = false
$this -> _legacyAPIRemap ( array (
'paramArray' => array (
'key' , 'id' , 'type' , 'sigOnly'
),
'request' => $this -> request ,
'named_params' => $this -> params [ 'named' ],
'ordered_url_params' => func_get_args (),
'injectedParams' => array (
'returnFormat' => 'xml'
),
'alias' => array (
'id' => 'eventid'
)
));
if ( ! empty ( $this -> _legacyParams [ 'sigOnly' ])) {
$this -> _legacyParams [ 'to_ids' ] = 1 ;
2018-07-19 11:48:22 +02:00
} else {
2020-06-29 21:09:47 +02:00
$this -> _legacyParams [ 'to_ids' ] = [ 0 , 1 ];
2018-07-19 11:48:22 +02:00
}
2020-06-29 21:09:47 +02:00
if ( ! empty ( $this -> _legacyParams [ 'type' ]) && $this -> _legacyParams [ 'type' ] === 'all' ) {
unset ( $this -> _legacyParams [ 'type' ]);
2018-07-19 11:48:22 +02:00
}
2020-06-29 21:09:47 +02:00
if ( ! empty ( $this -> _legacyParams [ 'type' ]) && $this -> _legacyParams [ 'type' ] === 'all' ) {
unset ( $this -> _legacyParams [ 'type' ]);
}
if ( $this -> response -> type () === 'application/json' ) {
$this -> _legacyParams [ 'returnFormat' ] = 'json' ;
}
return $this -> restSearch ();
2018-07-19 11:48:22 +02:00
}
2019-11-29 10:11:30 +01:00
public function text ()
2018-07-19 11:48:22 +02:00
{
2019-11-29 10:11:30 +01:00
$this -> _legacyAPIRemap ( array (
'paramArray' => array (
'key' , 'type' , 'tags' , 'eventId' , 'allowNonIDS' , 'from' , 'to' , 'last' , 'enforceWarninglist' , 'allowNotPublished'
),
'request' => $this -> request ,
'named_params' => $this -> params [ 'named' ],
'ordered_url_params' => func_get_args (),
'injectedParams' => array (
'returnFormat' => 'text'
),
'alias' => array (
'eventId' => 'eventid'
)
));
if ( ! empty ( $this -> _legacyParams [ 'allowNonIDS' ])) {
$this -> _legacyParams [ 'to_ids' ] = [ 0 , 1 ];
2018-07-19 11:48:22 +02:00
}
2019-11-29 10:11:30 +01:00
if ( ! empty ( $this -> _legacyParams [ 'allowNotPublished' ])) {
$this -> _legacyParams [ 'published' ] = [ 0 , 1 ];
2018-07-19 11:48:22 +02:00
}
2019-11-29 10:11:30 +01:00
if ( ! empty ( $this -> _legacyParams [ 'type' ]) && $this -> _legacyParams [ 'type' ] === 'all' ) {
unset ( $this -> _legacyParams [ 'type' ]);
2018-07-19 11:48:22 +02:00
}
2019-11-29 10:11:30 +01:00
return $this -> restSearch ();
2018-07-19 11:48:22 +02:00
}
2019-11-29 10:11:30 +01:00
public function rpz ()
2018-07-19 11:48:22 +02:00
{
2019-11-29 10:11:30 +01:00
$this -> _legacyAPIRemap ( array (
'paramArray' => array (
'key' , 'tags' , 'eventid' , 'from' , 'to' , 'policy' , 'walled_garden' , 'ns' ,
'email' , 'serial' , 'refresh' , 'retry' , 'expiry' , 'minimum_ttl' , 'ttl' ,
'enforceWarninglist' , 'ns_alt'
),
'request' => $this -> request ,
'named_params' => $this -> params [ 'named' ],
'ordered_url_params' => func_get_args (),
'injectedParams' => array (
'returnFormat' => 'rpz'
)
));
return $this -> restSearch ();
2018-07-19 11:48:22 +02:00
}
public function bro ( $key = 'download' , $type = 'all' , $tags = false , $eventId = false , $from = false , $to = false , $last = false , $enforceWarninglist = false )
{
if ( $this -> request -> is ( 'post' )) {
if ( $this -> request -> input ( 'json_decode' , true )) {
$data = $this -> request -> input ( 'json_decode' , true );
} else {
$data = $this -> request -> data ;
}
if ( ! empty ( $data ) && ! isset ( $data [ 'request' ])) {
$data = array ( 'request' => $data );
}
$paramArray = array ( 'type' , 'tags' , 'eventId' , 'from' , 'to' , 'last' , 'enforceWarninglist' );
foreach ( $paramArray as $p ) {
if ( isset ( $data [ 'request' ][ $p ])) {
${$p} = $data [ 'request' ][ $p ];
}
}
}
$simpleFalse = array ( 'type' , 'tags' , 'eventId' , 'from' , 'to' , 'last' , 'enforceWarninglist' );
foreach ( $simpleFalse as $sF ) {
if ( ! is_array ( ${$sF} ) && ( ${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower ( ${$sF} ) === 'false' )) {
${$sF} = false ;
}
}
if ( $type === 'null' || $type === '0' || $type === 'false' ) {
$type = 'all' ;
}
if ( $from ) {
$from = $this -> Attribute -> Event -> dateFieldCheck ( $from );
}
if ( $to ) {
$to = $this -> Attribute -> Event -> dateFieldCheck ( $to );
}
if ( $last ) {
$last = $this -> Attribute -> Event -> resolveTimeDelta ( $last );
}
if ( $key != 'download' ) {
// check if the key is valid -> search for users based on key
2021-09-26 12:23:23 +02:00
$user = $this -> _checkAuthUser ( $key );
2018-07-19 11:48:22 +02:00
if ( ! $user ) {
throw new UnauthorizedException ( __ ( 'This authentication key is not authorized to be used for exports. Contact your administrator.' ));
}
} else {
if ( ! $this -> Auth -> user ( 'id' )) {
throw new UnauthorizedException ( __ ( 'You have to be logged in to do that.' ));
}
}
$filename = 'misp.' . $type . '.intel' ;
if ( $eventId ) {
$filename = 'misp.' . $type . '.event_' . $eventId . '.intel' ;
}
$responseFile = implode ( PHP_EOL , $this -> Attribute -> bro ( $this -> Auth -> user (), $type , $tags , $eventId , $from , $to , $last , $enforceWarninglist )) . PHP_EOL ;
$this -> response -> body ( $responseFile );
$this -> response -> type ( 'txt' );
$this -> response -> download ( $filename );
return $this -> response ;
}
public function reportValidationIssuesAttributes ( $eventId = false )
{
// TODO improve performance of this function by eliminating the additional SQL query per attribute
// search for validation problems in the attributes
if ( ! self :: _isSiteAdmin ()) {
throw new NotFoundException ();
}
$this -> set ( 'result' , $this -> Attribute -> reportValidationIssuesAttributes ( $eventId ));
}
public function generateCorrelation ()
{
if ( ! self :: _isSiteAdmin () || ! $this -> request -> is ( 'post' )) {
throw new NotFoundException ();
}
if ( ! Configure :: read ( 'MISP.background_jobs' )) {
$k = $this -> Attribute -> generateCorrelation ();
$this -> Flash -> success ( __ ( 'All done. ' . $k . ' attributes processed.' ));
$this -> redirect ( array ( 'controller' => 'pages' , 'action' => 'display' , 'administration' ));
} else {
$job = ClassRegistry :: init ( 'Job' );
$job -> create ();
$data = array (
'worker' => 'default' ,
'job_type' => 'generate correlation' ,
'job_input' => 'All attributes' ,
'status' => 0 ,
'retries' => 0 ,
'org' => 'ADMIN' ,
'message' => 'Job created.' ,
);
$job -> save ( $data );
$jobId = $job -> id ;
$process_id = CakeResque :: enqueue (
'default' ,
'AdminShell' ,
array ( 'jobGenerateCorrelation' , $jobId ),
true
);
$job -> saveField ( 'process_id' , $process_id );
$this -> Flash -> success ( __ ( 'Job queued. You can view the progress if you navigate to the active jobs view (administration -> jobs).' ));
$this -> redirect ( array ( 'controller' => 'pages' , 'action' => 'display' , 'administration' ));
}
}
public function fetchViewValue ( $id , $field = null )
{
2019-06-13 09:16:34 +02:00
$validFields = array ( 'value' , 'comment' , 'type' , 'category' , 'to_ids' , 'distribution' , 'timestamp' , 'first_seen' , 'last_seen' );
2018-07-19 11:48:22 +02:00
if ( ! isset ( $field ) || ! in_array ( $field , $validFields )) {
throw new MethodNotAllowedException ( __ ( 'Invalid field requested.' ));
}
if ( ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ( __ ( 'This function can only be accessed via AJAX.' ));
}
2020-10-15 20:20:44 +02:00
$fieldsToFetch = [ 'id' , $field ];
if ( $field === 'value' ) {
$fieldsToFetch [] = 'to_ids' ; // for warninglist
$fieldsToFetch [] = 'type' ; // for view
$fieldsToFetch [] = 'category' ; // for view
}
2018-07-19 11:48:22 +02:00
$params = array (
2020-09-26 11:09:14 +02:00
'conditions' => array ( 'Attribute.id' => $id ),
2020-10-15 20:20:44 +02:00
'fields' => $fieldsToFetch ,
2020-09-26 11:09:14 +02:00
'contain' => [ 'Event' ],
'flatten' => 1 ,
2018-07-19 11:48:22 +02:00
);
$attribute = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), $params );
if ( empty ( $attribute )) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$attribute = $attribute [ 0 ];
$result = $attribute [ 'Attribute' ][ $field ];
2020-07-20 10:10:47 +02:00
if ( $field === 'distribution' ) {
$result = $this -> Attribute -> shortDist [ $result ];
} elseif ( $field === 'to_ids' ) {
2018-07-19 11:48:22 +02:00
$result = ( $result == 0 ? 'No' : 'Yes' );
2020-07-20 10:10:47 +02:00
} elseif ( $field === 'timestamp' ) {
2018-07-19 11:48:22 +02:00
if ( isset ( $result )) {
$result = date ( 'Y-m-d' , $result );
} else {
echo ' ' ;
}
2020-10-15 20:20:44 +02:00
} elseif ( $field === 'value' ) {
$this -> loadModel ( 'Warninglist' );
$attribute [ 'Attribute' ] = $this -> Warninglist -> checkForWarning ( $attribute [ 'Attribute' ]);
2018-07-19 11:48:22 +02:00
}
2020-10-15 20:20:44 +02:00
2018-07-19 11:48:22 +02:00
$this -> set ( 'value' , $result );
2020-09-26 11:09:14 +02:00
$this -> set ( 'object' , $attribute );
$this -> set ( 'field' , $field );
2018-07-19 11:48:22 +02:00
$this -> layout = 'ajax' ;
$this -> render ( 'ajax/attributeViewFieldForm' );
}
public function fetchEditForm ( $id , $field = null )
{
2019-06-13 15:12:59 +02:00
$validFields = array ( 'value' , 'comment' , 'type' , 'category' , 'to_ids' , 'distribution' , 'first_seen' , 'last_seen' );
2018-07-19 11:48:22 +02:00
if ( ! isset ( $field ) || ! in_array ( $field , $validFields )) {
throw new MethodNotAllowedException ( __ ( 'Invalid field requested.' ));
}
if ( ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ( __ ( 'This function can only be accessed via AJAX.' ));
}
$fields = array ( 'id' , 'distribution' , 'event_id' );
if ( $field == 'category' || $field == 'type' ) {
$fields [] = 'type' ;
$fields [] = 'category' ;
} else {
$fields [] = $field ;
}
$params = array (
'conditions' => array ( 'Attribute.id' => $id ),
'fields' => $fields ,
'flatten' => 1 ,
'contain' => array (
'Event' => array (
'fields' => array ( 'distribution' , 'id' , 'user_id' , 'orgc_id' ),
)
)
);
$attribute = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), $params );
if ( empty ( $attribute )) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$attribute = $attribute [ 0 ];
2020-07-20 10:10:47 +02:00
if ( ! $this -> __canModifyEvent ( $attribute )) {
throw new ForbiddenException ( __ ( 'You do not have permission to do that' ));
2018-07-19 11:48:22 +02:00
}
$this -> layout = 'ajax' ;
2020-07-20 10:10:47 +02:00
if ( $field === 'distribution' ) {
2018-07-19 11:48:22 +02:00
$distributionLevels = $this -> Attribute -> shortDist ;
unset ( $distributionLevels [ 4 ]);
$this -> set ( 'distributionLevels' , $distributionLevels );
2020-07-20 10:10:47 +02:00
} elseif ( $field === 'category' ) {
2018-07-19 11:48:22 +02:00
$typeCategory = array ();
foreach ( $this -> Attribute -> categoryDefinitions as $k => $category ) {
foreach ( $category [ 'types' ] as $type ) {
$typeCategory [ $type ][] = $k ;
}
}
$this -> set ( 'typeCategory' , $typeCategory );
2020-07-20 10:10:47 +02:00
} elseif ( $field === 'type' ) {
2018-07-19 11:48:22 +02:00
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
}
$this -> set ( 'object' , $attribute [ 'Attribute' ]);
$fieldURL = ucfirst ( $field );
$this -> render ( 'ajax/attributeEdit' . $fieldURL . 'Form' );
}
public function attributeReplace ( $id )
{
if ( ! $this -> userRole [ 'perm_add' ]) {
2020-07-20 10:10:47 +02:00
throw new ForbiddenException ( __ ( 'Event not found or you don\'t have permissions to create attributes' ));
2018-07-19 11:48:22 +02:00
}
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'Event.id' => $id ),
2020-07-20 10:10:47 +02:00
'fields' => array ( 'id' , 'orgc_id' , 'distribution' , 'user_id' ),
2018-07-19 11:48:22 +02:00
'recursive' => - 1
));
2020-07-20 10:10:47 +02:00
if ( empty ( $event ) || ! $this -> __canModifyEvent ( $event )) {
2018-07-19 11:48:22 +02:00
throw new MethodNotAllowedException ( __ ( 'Event not found or you don\'t have permissions to create attributes' ));
}
$this -> set ( 'event_id' , $id );
if ( $this -> request -> is ( 'get' )) {
$this -> layout = 'ajax' ;
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $id ;
// combobox for types
$types = array_keys ( $this -> Attribute -> typeDefinitions );
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = array_keys ( $this -> Attribute -> categoryDefinitions );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
2020-07-04 10:38:50 +02:00
$this -> set ( 'categories' , $categories );
2018-07-19 11:48:22 +02:00
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
}
if ( $this -> request -> is ( 'post' )) {
if ( ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ( __ ( 'This action can only be accessed via AJAX.' ));
}
$newValues = explode ( PHP_EOL , $this -> request -> data [ 'Attribute' ][ 'value' ]);
$category = $this -> request -> data [ 'Attribute' ][ 'category' ];
$type = $this -> request -> data [ 'Attribute' ][ 'type' ];
$to_ids = $this -> request -> data [ 'Attribute' ][ 'to_ids' ];
if ( ! $this -> _isSiteAdmin () && $this -> Auth -> user ( 'org_id' ) != $event [ 'Event' ][ 'orgc_id' ] && ! $this -> userRole [ 'perm_add' ]) {
throw new MethodNotAllowedException ( __ ( 'You are not authorised to do that.' ));
}
$oldAttributes = $this -> Attribute -> find ( 'all' , array (
'conditions' => array (
'event_id' => $id ,
'category' => $category ,
'type' => $type ,
),
'fields' => array ( 'id' , 'event_id' , 'category' , 'type' , 'value' ),
'recursive' => - 1 ,
));
$results = array ( 'untouched' => count ( $oldAttributes ), 'created' => 0 , 'deleted' => 0 , 'createdFail' => 0 , 'deletedFail' => 0 );
$newValues = array_map ( 'trim' , $newValues );
foreach ( $newValues as $value ) {
$found = false ;
foreach ( $oldAttributes as $old ) {
if ( $value == $old [ 'Attribute' ][ 'value' ]) {
$found = true ;
}
}
if ( ! $found ) {
$attribute = array (
'value' => $value ,
'event_id' => $id ,
'category' => $category ,
'type' => $type ,
'distribution' => $event [ 'Event' ][ 'distribution' ],
'to_ids' => $to_ids ,
);
$this -> Attribute -> create ();
if ( $this -> Attribute -> save ( array ( 'Attribute' => $attribute ))) {
$results [ 'created' ] ++ ;
} else {
$results [ 'createdFail' ] ++ ;
}
}
}
foreach ( $oldAttributes as $old ) {
if ( ! in_array ( $old [ 'Attribute' ][ 'value' ], $newValues )) {
if ( $this -> Attribute -> delete ( $old [ 'Attribute' ][ 'id' ])) {
$results [ 'deleted' ] ++ ;
$results [ 'untouched' ] -- ;
} else {
$results [ 'deletedFail' ] ++ ;
}
}
}
$message = '' ;
$success = true ;
if (( $results [ 'created' ] > 0 || $results [ 'deleted' ] > 0 ) && $results [ 'createdFail' ] == 0 && $results [ 'deletedFail' ] == 0 ) {
$message .= 'Update completed without any issues.' ;
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'Event.id' => $id ),
'recursive' => - 1
));
$event [ 'Event' ][ 'published' ] = 0 ;
$date = new DateTime ();
$event [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> Event -> save ( $event );
} else {
$message .= 'Update completed with some errors.' ;
$success = false ;
}
if ( $results [ 'created' ]) {
$message .= $results [ 'created' ] . ' attribute' . $this -> __checkCountForOne ( $results [ 'created' ]) . ' created. ' ;
}
if ( $results [ 'createdFail' ]) {
$message .= $results [ 'createdFail' ] . ' attribute' . $this -> __checkCountForOne ( $results [ 'createdFail' ]) . ' could not be created. ' ;
}
if ( $results [ 'deleted' ]) {
$message .= $results [ 'deleted' ] . ' attribute' . $this -> __checkCountForOne ( $results [ 'deleted' ]) . ' deleted.' ;
}
if ( $results [ 'deletedFail' ]) {
$message .= $results [ 'deletedFail' ] . ' attribute' . $this -> __checkCountForOne ( $results [ 'deletedFail' ]) . ' could not be deleted. ' ;
}
$message .= $results [ 'untouched' ] . ' attributes left untouched. ' ;
$this -> autoRender = false ;
$this -> layout = 'ajax' ;
if ( $success ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $message )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => $message )), 'status' => 200 , 'type' => 'json' ));
}
}
}
private function __checkCountForOne ( $number )
{
if ( $number != 1 ) {
return 's' ;
}
return '' ;
}
// download a sample by passing along an md5
public function downloadSample ( $hash = false , $allSamples = false , $eventID = false )
{
if ( ! $this -> userRole [ 'perm_auth' ]) {
throw new MethodNotAllowedException ( __ ( 'This functionality requires API key access.' ));
}
$error = false ;
if ( $this -> response -> type () === 'application/json' ) {
$data = $this -> request -> input ( 'json_decode' , true );
} elseif ( $this -> response -> type () === 'application/xml' ) {
$data = $this -> request -> data ;
} else {
throw new BadRequestException ( __ ( 'This action is for the API only. Please refer to the automation page for information on how to use it.' ));
}
if ( ! $hash && isset ( $data [ 'request' ][ 'hash' ])) {
$hash = $data [ 'request' ][ 'hash' ];
}
if ( ! $allSamples && isset ( $data [ 'request' ][ 'allSamples' ])) {
$allSamples = $data [ 'request' ][ 'allSamples' ];
}
if ( ! $eventID && isset ( $data [ 'request' ][ 'eventID' ])) {
$eventID = $data [ 'request' ][ 'eventID' ];
}
if ( ! $eventID && ! $hash ) {
throw new MethodNotAllowedException ( __ ( 'No hash or event ID received. You need to set at least one of the two.' ));
}
if ( ! $hash ) {
$allSamples = true ;
}
$simpleFalse = array ( 'hash' , 'allSamples' , 'eventID' );
foreach ( $simpleFalse as $sF ) {
if ( ! is_array ( ${$sF} ) && ( ${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower ( ${$sF} ) === 'false' )) {
${$sF} = false ;
}
}
// valid combinations of settings are:
// hash
// eventID + all samples
// hash + eventID
// hash + eventID + all samples
$searchConditions = array ();
$types = array ();
if ( $hash ) {
$validTypes = $this -> Attribute -> resolveHashType ( $hash );
if ( $allSamples ) {
if ( empty ( $validTypes )) {
$error = 'Invalid hash format (valid options are ' . implode ( ', ' , array_keys ( $this -> Attribute -> hashTypes )) . ')' ;
} else {
foreach ( $validTypes as $t ) {
if ( $t == 'md5' ) {
$types = array_merge ( $types , array ( 'malware-sample' , 'filename|md5' , 'md5' ));
} else {
$types = array_merge ( $types , array ( 'filename|' . $t , $t ));
}
}
}
if ( empty ( $error )) {
$event_ids = $this -> Attribute -> find ( 'list' , array (
'recursive' => - 1 ,
'contain' => array ( 'Event' ),
'fields' => array ( 'Event.id' ),
'conditions' => array (
'OR' => array (
'AND' => array (
'LOWER(Attribute.value1) LIKE' => strtolower ( $hash ),
'Attribute.value2' => '' ,
),
'LOWER(Attribute.value2) LIKE' => strtolower ( $hash )
)
),
));
$searchConditions = array (
'AND' => array ( 'Event.id' => array_values ( $event_ids ))
);
if ( empty ( $event_ids )) {
$error = 'No hits with the given parameters.' ;
}
}
} else {
if ( ! in_array ( 'md5' , $validTypes )) {
$error = 'Only MD5 hashes can be used to fetch malware samples at this point in time.' ;
}
if ( empty ( $error )) {
$searchConditions = array ( 'AND' => array ( 'LOWER(Attribute.value2) LIKE' => strtolower ( $hash )));
}
}
}
if ( ! empty ( $eventID )) {
$searchConditions [ 'AND' ][] = array ( 'Event.id' => $eventID );
}
if ( empty ( $error )) {
$attributes = $this -> Attribute -> fetchAttributes (
$this -> Auth -> user (),
array (
'fields' => array ( 'Attribute.event_id' , 'Attribute.id' , 'Attribute.value1' , 'Attribute.value2' , 'Event.info' ),
'conditions' => array (
'AND' => array (
$searchConditions ,
array ( 'Attribute.type' => 'malware-sample' )
)
),
'contain' => array ( 'Event' ),
'flatten' => 1
)
);
if ( empty ( $attributes )) {
$error = 'No hits with the given parameters.' ;
}
$results = array ();
foreach ( $attributes as $attribute ) {
$found = false ;
foreach ( $results as $previous ) {
if ( $previous [ 'md5' ] == $attribute [ 'Attribute' ][ 'value2' ]) {
$found = true ;
}
}
if ( ! $found ) {
$results [] = array (
'md5' => $attribute [ 'Attribute' ][ 'value2' ],
'base64' => $this -> Attribute -> base64EncodeAttachment ( $attribute [ 'Attribute' ]),
'filename' => $attribute [ 'Attribute' ][ 'value1' ],
'attribute_id' => $attribute [ 'Attribute' ][ 'id' ],
'event_id' => $attribute [ 'Attribute' ][ 'event_id' ],
'event_info' => $attribute [ 'Event' ][ 'info' ],
);
}
}
if ( $error ) {
$this -> set ( 'message' , $error );
$this -> set ( '_serialize' , array ( 'message' ));
} else {
$this -> set ( 'result' , $results );
$this -> set ( '_serialize' , array ( 'result' ));
}
} else {
$this -> set ( 'message' , $error );
$this -> set ( '_serialize' , array ( 'message' ));
}
}
public function pruneOrphanedAttributes ()
{
if ( ! $this -> _isSiteAdmin () || ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( __ ( 'You are not authorised to do that.' ));
}
$events = array_keys ( $this -> Attribute -> Event -> find ( 'list' ));
$orphans = $this -> Attribute -> find ( 'list' , array ( 'conditions' => array ( 'Attribute.event_id !=' => $events )));
if ( count ( $orphans ) > 0 ) {
$this -> Attribute -> deleteAll ( array ( 'Attribute.event_id !=' => $events ), false , true );
}
$this -> Flash -> success ( 'Removed ' . count ( $orphans ) . ' attribute(s).' );
$this -> redirect ( Router :: url ( $this -> referer (), true ));
}
public function checkOrphanedAttributes ()
{
if ( ! $this -> _isSiteAdmin ()) {
throw new MethodNotAllowedException ( __ ( 'You are not authorised to do that.' ));
}
$this -> loadModel ( 'Attribute' );
$events = array_keys ( $this -> Attribute -> Event -> find ( 'list' ));
$orphans = $this -> Attribute -> find ( 'list' , array ( 'conditions' => array ( 'Attribute.event_id !=' => $events )));
return new CakeResponse ( array ( 'body' => count ( $orphans ), 'status' => 200 , 'type' => 'json' ));
}
public function updateAttributeValues ( $script )
{
if ( ! $this -> _isSiteAdmin () || ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ( __ ( 'You are not authorised to do that.' ));
}
switch ( $script ) {
case 'urlSanitisation' :
$replaceConditions = array (
array ( 'search' => 'UPPER(Attribute.value1) LIKE' , 'from' => 'HXXP' , 'to' => 'http' , 'ci' => true , 'condition' => 'startsWith' ),
array ( 'search' => 'Attribute.value1 LIKE' , 'from' => '[.]' , 'to' => '.' , 'ci' => false , 'condition' => 'contains' ),
);
break ;
default :
throw new Exception ( __ ( 'Invalid script.' ));
}
$counter = 0 ;
foreach ( $replaceConditions as $rC ) {
$searchPattern = '' ;
if ( in_array ( $rC [ 'condition' ], array ( 'endsWith' , 'contains' ))) {
$searchPattern .= '%' ;
}
$searchPattern .= $rC [ 'from' ];
if ( in_array ( $rC [ 'condition' ], array ( 'startsWith' , 'contains' ))) {
$searchPattern .= '%' ;
}
$attributes = $this -> Attribute -> find ( 'all' , array ( 'conditions' => array ( $rC [ 'search' ] => $searchPattern ), 'recursive' => - 1 ));
foreach ( $attributes as $attribute ) {
$regex = '/' ;
if ( ! in_array ( $rC [ 'condition' ], array ( 'startsWith' , 'contains' ))) {
$regex .= '^' ;
}
$regex .= $rC [ 'from' ];
if ( ! in_array ( $rC [ 'condition' ], array ( 'endsWith' , 'contains' ))) {
$regex .= '$' ;
}
$regex .= '/' ;
if ( $rC [ 'ci' ]) {
$regex .= 'i' ;
}
$attribute [ 'Attribute' ][ 'value' ] = preg_replace ( $regex , $rC [ 'to' ], $attribute [ 'Attribute' ][ 'value' ]);
$this -> Attribute -> save ( $attribute );
$counter ++ ;
}
}
$this -> Flash -> success ( 'Updated ' . $counter . ' attribute(s).' );
$this -> redirect ( '/pages/display/administration' );
}
2018-11-07 11:26:08 +01:00
public function hoverEnrichment ( $id , $persistent = false )
2018-07-19 11:48:22 +02:00
{
$attribute = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array ( 'conditions' => array ( 'Attribute.id' => $id ), 'flatten' => 1 ));
if ( empty ( $attribute )) {
throw new NotFoundException ( __ ( 'Invalid Attribute' ));
}
$this -> loadModel ( 'Module' );
$modules = $this -> Module -> getEnabledModules ( $this -> Auth -> user ());
$validTypes = array ();
if ( isset ( $modules [ 'hover_type' ][ $attribute [ 0 ][ 'Attribute' ][ 'type' ]])) {
$validTypes = $modules [ 'hover_type' ][ $attribute [ 0 ][ 'Attribute' ][ 'type' ]];
}
$resultArray = array ();
foreach ( $validTypes as $type ) {
$options = array ();
$found = false ;
foreach ( $modules [ 'modules' ] as $temp ) {
2020-10-07 17:55:29 +02:00
if ( $temp [ 'name' ] === $type ) {
2018-07-19 11:48:22 +02:00
$found = true ;
2020-10-07 17:55:29 +02:00
$format = isset ( $temp [ 'mispattributes' ][ 'format' ]) ? $temp [ 'mispattributes' ][ 'format' ] : 'simplified' ;
2018-07-19 11:48:22 +02:00
if ( isset ( $temp [ 'meta' ][ 'config' ])) {
foreach ( $temp [ 'meta' ][ 'config' ] as $conf ) {
$options [ $conf ] = Configure :: read ( 'Plugin.Enrichment_' . $type . '_' . $conf );
}
}
2019-03-11 23:47:03 +01:00
break ;
2018-07-19 11:48:22 +02:00
}
}
if ( ! $found ) {
throw new MethodNotAllowedException ( __ ( 'No valid enrichment options found for this attribute.' ));
}
2019-03-11 23:47:03 +01:00
$data = array ( 'module' => $type );
2018-11-23 14:11:33 +01:00
if ( $persistent ) {
$data [ 'persistent' ] = 1 ;
}
2018-07-19 11:48:22 +02:00
if ( ! empty ( $options )) {
$data [ 'config' ] = $options ;
}
2019-03-11 23:47:03 +01:00
if ( $format == 'misp_standard' ) {
2019-07-12 10:44:20 +02:00
$data [ 'attribute' ] = in_array ( 'value' , $attribute ) ? $attribute : $attribute [ 0 ][ 'Attribute' ];
2019-03-11 23:47:03 +01:00
} else {
$data [ $attribute [ 0 ][ 'Attribute' ][ 'type' ]] = $attribute [ 0 ][ 'Attribute' ][ 'value' ];
}
2020-10-22 19:42:47 +02:00
$result = $this -> Module -> queryModuleServer ( $data , true );
2018-07-19 11:48:22 +02:00
if ( $result ) {
if ( ! is_array ( $result )) {
2020-10-08 14:07:59 +02:00
$resultArray [ $type ] = [ 'error' => $result ];
continue ;
2018-07-19 11:48:22 +02:00
}
} else {
// TODO: i18n?
2020-10-08 14:07:59 +02:00
$resultArray [ $type ] = [ 'error' => 'Enrichment service not reachable.' ];
2018-07-19 11:48:22 +02:00
continue ;
}
2019-04-15 17:16:00 +02:00
$current_result = array ();
if ( isset ( $result [ 'results' ][ 'Object' ])) {
if ( ! empty ( $result [ 'results' ][ 'Object' ])) {
$objects = array ();
2020-10-07 17:55:29 +02:00
foreach ( $result [ 'results' ][ 'Object' ] as $object ) {
2019-04-15 17:16:00 +02:00
if ( isset ( $object [ 'Attribute' ]) && ! empty ( $object [ 'Attribute' ])) {
$object_attributes = array ();
foreach ( $object [ 'Attribute' ] as $object_attribute ) {
2020-10-07 19:53:56 +02:00
$object_attributes [] = [
'object_relation' => $object_attribute [ 'object_relation' ],
'value' => $object_attribute [ 'value' ],
'type' => $object_attribute [ 'type' ],
];
2019-04-15 17:16:00 +02:00
}
2020-10-07 19:53:56 +02:00
$objects [] = array ( 'name' => $object [ 'name' ], 'Attribute' => $object_attributes );
2019-04-15 17:16:00 +02:00
}
}
2020-10-07 17:55:29 +02:00
$current_result [ 'Object' ] = $objects ;
2019-04-15 17:16:00 +02:00
}
unset ( $result [ 'results' ][ 'Object' ]);
}
if ( isset ( $result [ 'results' ][ 'Attribute' ])) {
if ( ! empty ( $result [ 'results' ][ 'Attribute' ])) {
$attributes = array ();
2019-10-04 14:42:46 +02:00
foreach ( $result [ 'results' ][ 'Attribute' ] as $result_attribute ) {
$attributes [] = array ( 'type' => $result_attribute [ 'type' ], 'value' => $result_attribute [ 'value' ]);
2019-04-15 17:16:00 +02:00
}
$current_result [ 'Attribute' ] = $attributes ;
}
unset ( $result [ 'results' ][ 'Attribute' ]);
}
$resultArray [ $type ] = $current_result ;
2018-07-19 11:48:22 +02:00
if ( ! empty ( $result [ 'results' ])) {
foreach ( $result [ 'results' ] as $r ) {
if ( is_array ( $r [ 'values' ]) && ! empty ( $r [ 'values' ])) {
$tempArray = array ();
foreach ( $r [ 'values' ] as $k => $v ) {
if ( is_array ( $v )) {
$v = 'Array returned' ;
}
2018-09-05 11:28:18 +02:00
$tempArray [ $k ] = $v ;
2018-07-19 11:48:22 +02:00
}
2019-02-13 19:19:57 +01:00
$resultArray [ $type ][] = array ( $type => $tempArray );
2018-07-19 11:48:22 +02:00
} elseif ( $r [ 'values' ] == null ) {
2019-02-13 19:19:57 +01:00
$resultArray [ $type ][] = array ( $type => 'No result' );
2018-07-19 11:48:22 +02:00
} else {
2019-02-13 19:19:57 +01:00
$resultArray [ $type ][] = array ( $type => $r [ 'values' ]);
2018-07-19 11:48:22 +02:00
}
}
}
}
2020-10-07 18:57:10 +02:00
$this -> set ( 'persistent' , $persistent );
2018-07-19 11:48:22 +02:00
$this -> set ( 'results' , $resultArray );
$this -> layout = 'ajax' ;
$this -> render ( 'ajax/hover_enrichment' );
}
public function describeTypes ()
{
$result = array ();
foreach ( $this -> Attribute -> typeDefinitions as $key => $value ) {
$result [ 'sane_defaults' ][ $key ] = array ( 'default_category' => $value [ 'default_category' ], 'to_ids' => $value [ 'to_ids' ]);
}
$result [ 'types' ] = array_keys ( $this -> Attribute -> typeDefinitions );
$result [ 'categories' ] = array_keys ( $this -> Attribute -> categoryDefinitions );
foreach ( $this -> Attribute -> categoryDefinitions as $cat => $data ) {
$result [ 'category_type_mappings' ][ $cat ] = $data [ 'types' ];
}
2021-06-28 14:28:20 +02:00
return $this -> RestResponse -> viewData ([ 'result' => $result ], 'json' );
2018-07-19 11:48:22 +02:00
}
public function attributeStatistics ( $type = 'type' , $percentage = false )
{
$validTypes = array ( 'type' , 'category' );
if ( ! in_array ( $type , $validTypes )) {
throw new MethodNotAllowedException ( __ ( 'Invalid type requested.' ));
}
$totalAttributes = $this -> Attribute -> find ( 'count' , array ());
$attributes = $this -> Attribute -> find ( 'all' , array (
2021-02-19 14:26:43 +01:00
'recursive' => - 1 ,
'fields' => array ( $type , 'COUNT(id) as attribute_count' ),
'group' => array ( $type ),
'order' => ''
2018-07-19 11:48:22 +02:00
));
$results = array ();
foreach ( $attributes as $attribute ) {
if ( $percentage ) {
$results [ $attribute [ 'Attribute' ][ $type ]] = round ( 100 * $attribute [ 0 ][ 'attribute_count' ] / $totalAttributes , 3 ) . '%' ;
} else {
$results [ $attribute [ 'Attribute' ][ $type ]] = $attribute [ 0 ][ 'attribute_count' ];
}
}
ksort ( $results );
2021-06-28 14:28:20 +02:00
return $this -> RestResponse -> viewData ( $results , 'json' );
2018-07-19 11:48:22 +02:00
}
public function addTag ( $id = false , $tag_id = false )
{
$rearrangeRules = array (
'request' => false ,
'Attribute' => false ,
'tag_id' => 'tag' ,
'attribute_id' => 'attribute' ,
'id' => 'attribute'
);
$RearrangeTool = new RequestRearrangeTool ();
$this -> request -> data = $RearrangeTool -> rearrangeArray ( $this -> request -> data , $rearrangeRules );
2021-10-06 18:26:59 +02:00
$local = empty ( $this -> request -> params [ 'named' ][ 'local' ]) ? 0 : 1 ;
2019-03-20 11:21:40 +01:00
if ( ! $this -> request -> is ( 'post' )) {
2019-11-13 14:07:50 +01:00
if ( $id === false ) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
2019-07-08 11:39:41 +02:00
$this -> set ( 'local' , $local );
2019-03-20 11:21:40 +01:00
$this -> set ( 'object_id' , $id );
$this -> set ( 'scope' , 'Attribute' );
$this -> layout = false ;
$this -> autoRender = false ;
$this -> render ( '/Events/add_tag' );
} else {
2019-11-13 14:07:50 +01:00
if ( $id === false ) {
if ( ! isset ( $this -> request -> data [ 'attribute' ])) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$id = $this -> request -> data [ 'attribute' ];
}
if ( $id === 'selected' ) {
if ( ! isset ( $this -> request -> data [ 'attribute_ids' ])) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$idList = json_decode ( $this -> request -> data [ 'attribute_ids' ], true );
}
2019-03-20 11:21:40 +01:00
if ( $tag_id === false ) {
2019-10-04 15:34:18 +02:00
if ( ! isset ( $this -> request -> data [ 'tag' ])) {
throw new NotFoundException ( __ ( 'Invalid tag' ));
}
2019-03-20 11:21:40 +01:00
$tag_id = $this -> request -> data [ 'tag' ];
}
if ( ! is_numeric ( $tag_id )) {
if ( preg_match ( '/^collection_[0-9]+$/i' , $tag_id )) {
$tagChoice = explode ( '_' , $tag_id )[ 1 ];
$this -> loadModel ( 'TagCollection' );
$tagCollection = $this -> TagCollection -> fetchTagCollection ( $this -> Auth -> user (), array ( 'conditions' => array ( 'TagCollection.id' => $tagChoice )));
if ( empty ( $tagCollection )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Tag Collection.' )), 'status' => 200 , 'type' => 'json' ));
}
2021-10-06 18:26:59 +02:00
$tag_id_list = array_column ( $tagCollection [ 0 ][ 'TagCollectionTag' ], 'tag_id' );
2019-01-09 14:19:14 +01:00
} else {
2019-03-20 11:21:40 +01:00
// try to parse json array
$tag_ids = json_decode ( $tag_id );
if ( $tag_ids !== null ) { // can decode json
$tag_id_list = array ();
foreach ( $tag_ids as $tag_id ) {
if ( preg_match ( '/^collection_[0-9]+$/i' , $tag_id )) {
$tagChoice = explode ( '_' , $tag_id )[ 1 ];
$this -> loadModel ( 'TagCollection' );
$tagCollection = $this -> TagCollection -> fetchTagCollection ( $this -> Auth -> user (), array ( 'conditions' => array ( 'TagCollection.id' => $tagChoice )));
if ( empty ( $tagCollection )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Tag Collection.' )), 'status' => 200 , 'type' => 'json' ));
}
2021-10-06 18:26:59 +02:00
$tag_id_list = array_column ( $tagCollection [ 0 ][ 'TagCollectionTag' ], 'tag_id' );
2019-03-20 11:21:40 +01:00
} else {
$tag_id_list [] = $tag_id ;
}
}
} else {
2021-10-24 10:31:04 +02:00
$tagId = $this -> Attribute -> AttributeTag -> Tag -> lookupTagIdForUser ( $this -> Auth -> user (), trim ( $tag_id ));
if ( empty ( $tagId )) {
2019-03-20 11:21:40 +01:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Tag.' )), 'status' => 200 , 'type' => 'json' ));
}
2021-10-24 10:31:04 +02:00
$tag_id = $tagId ;
2019-01-09 14:19:14 +01:00
}
2019-01-01 16:38:57 +01:00
}
2018-07-19 11:48:22 +02:00
}
2019-03-20 11:21:40 +01:00
if ( ! isset ( $idList )) {
$idList = array ( $id );
2018-12-11 11:36:40 +01:00
}
2019-03-20 11:21:40 +01:00
if ( empty ( $tag_id_list )) {
$tag_id_list = array ( $tag_id );
2018-07-19 11:48:22 +02:00
}
2021-10-06 18:26:59 +02:00
$conditions = [ 'Tag.id' => $tag_id_list ];
if ( ! $this -> _isSiteAdmin ()) {
$conditions [ 'Tag.org_id' ] = array ( 0 , $this -> Auth -> user ( 'org_id' ));
$conditions [ 'Tag.user_id' ] = array ( 0 , $this -> Auth -> user ( 'id' ));
}
$tags = $this -> Attribute -> AttributeTag -> Tag -> find ( 'list' , array (
'conditions' => $conditions ,
'fields' => [ 'Tag.id' , 'Tag.name' ],
));
2019-03-20 11:21:40 +01:00
$success = 0 ;
$fails = 0 ;
2020-08-15 16:36:32 +02:00
$this -> Taxonomy = ClassRegistry :: init ( 'Taxonomy' );
2019-03-20 11:21:40 +01:00
foreach ( $idList as $id ) {
2021-10-06 18:26:59 +02:00
$attribute = $this -> Attribute -> fetchAttributeSimple ( $this -> Auth -> user (), [
'conditions' => array ( 'Attribute.id' => $id , 'Attribute.deleted' => 0 ),
]);
if ( empty ( $attribute )) {
2019-03-20 11:21:40 +01:00
throw new NotFoundException ( __ ( 'Invalid attribute' ));
2019-09-20 15:59:20 +02:00
}
2021-10-06 18:26:59 +02:00
if ( ! $this -> __canModifyTag ( $attribute , $local )) {
2021-03-24 10:21:05 +01:00
$fails ++ ;
continue ;
}
2019-03-20 11:21:40 +01:00
if ( ! $this -> _isRest ()) {
2021-10-06 18:26:59 +02:00
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $attribute [ 'Event' ][ 'id' ]);
2019-03-20 11:21:40 +01:00
}
2021-10-06 18:26:59 +02:00
$changeTimestamp = false ;
2019-03-20 11:21:40 +01:00
foreach ( $tag_id_list as $tag_id ) {
2021-10-06 18:26:59 +02:00
if ( ! isset ( $tags [ $tag_id ])) {
2020-08-15 16:36:32 +02:00
// Tag not found or user don't have permission to add it.
$fails ++ ;
continue ;
}
2021-10-06 18:26:59 +02:00
$tagName = $tags [ $tag_id ];
$found = $this -> Attribute -> AttributeTag -> hasAny ([
'attribute_id' => $id ,
'tag_id' => $tag_id ,
]);
if ( $found ) {
2020-08-15 16:36:32 +02:00
// Tag is already assigned to given attribute.
2019-03-20 11:21:40 +01:00
$fails ++ ;
continue ;
}
2021-10-06 18:26:59 +02:00
$tagsOnAttribute = $this -> Attribute -> AttributeTag -> find ( 'column' , array (
2019-11-04 15:12:55 +01:00
'conditions' => array (
'AttributeTag.attribute_id' => $id ,
2021-10-06 18:26:59 +02:00
'AttributeTag.local' => $local ,
2019-11-04 15:12:55 +01:00
),
'contain' => 'Tag' ,
'fields' => array ( 'Tag.name' ),
));
2021-10-06 18:26:59 +02:00
$exclusiveTestPassed = $this -> Taxonomy -> checkIfNewTagIsAllowedByTaxonomy ( $tagName , $tagsOnAttribute );
2019-11-04 15:46:53 +01:00
if ( ! $exclusiveTestPassed ) {
2019-11-04 15:12:55 +01:00
$fails ++ ;
continue ;
}
2019-03-20 11:21:40 +01:00
$this -> Attribute -> AttributeTag -> create ();
2021-10-06 18:26:59 +02:00
if ( $this -> Attribute -> AttributeTag -> save ( array ( 'attribute_id' => $id , 'tag_id' => $tag_id , 'event_id' => $attribute [ 'Event' ][ 'id' ], 'local' => $local ))) {
2019-07-08 11:39:41 +02:00
if ( ! $local ) {
2021-10-06 18:26:59 +02:00
$changeTimestamp = true ;
2019-07-08 11:39:41 +02:00
}
2019-03-20 11:21:40 +01:00
$log = ClassRegistry :: init ( 'Log' );
2019-07-08 11:39:41 +02:00
$log -> createLogEntry (
$this -> Auth -> user (),
'tag' ,
'Attribute' ,
$id ,
sprintf (
'Attached%s tag (%s) "%s" to attribute (%s)' ,
$local ? ' local' : '' ,
$tag_id ,
2021-10-06 18:26:59 +02:00
$tagName ,
2019-07-08 11:39:41 +02:00
$id
),
sprintf (
'Attribute (%s) tagged as Tag (%s)%s' ,
$id ,
$tag_id ,
$local ? ' locally' : ''
)
);
2019-03-20 11:21:40 +01:00
$success ++ ;
} else {
$fails ++ ;
}
2019-01-01 16:38:57 +01:00
}
2021-10-06 18:26:59 +02:00
if ( $changeTimestamp ) {
$attribute [ 'Event' ][ 'published' ] = 0 ;
$date = new DateTime ();
$attribute [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
$result = $this -> Attribute -> Event -> save ( $attribute [ 'Event' ]);
$attribute [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
if ( $attribute [ 'Attribute' ][ 'object_id' ] != 0 ) {
$this -> Attribute -> Object -> updateTimestamp ( $attribute [ 'Attribute' ][ 'object_id' ], $date -> getTimestamp ());
}
$this -> Attribute -> save ( $attribute [ 'Attribute' ]);
}
2018-07-19 11:48:22 +02:00
}
2021-10-06 18:26:59 +02:00
if ( $fails === 0 ) {
2020-08-15 16:36:32 +02:00
$message = __n ( 'Tag added.' , '%s tags added' , $success , $success );
2019-03-20 11:21:40 +01:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $message , 'check_publish' => true )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
} else {
2020-08-15 16:36:32 +02:00
$message = __n ( 'Tag could not be added.' , '%s tags could not be added.' , $fails , $fails );
2019-03-20 11:21:40 +01:00
if ( $success > 0 ) {
2020-08-15 15:49:17 +02:00
$message .= __n ( ' However, %s tag was added.' , ' However, %s tags were added.' , $success , $success );
2019-03-20 11:21:40 +01:00
}
2021-10-06 18:26:59 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $message )), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
}
}
}
public function removeTag ( $id = false , $tag_id = false )
{
if ( ! $this -> request -> is ( 'post' )) {
2020-08-15 15:49:17 +02:00
$attribute = $this -> __fetchAttribute ( $id );
if ( ! $attribute ) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$attributeTag = $this -> Attribute -> AttributeTag -> find ( 'first' , array (
'conditions' => array (
'attribute_id' => $attribute [ 'Attribute' ][ 'id' ],
'tag_id' => $tag_id ,
),
'contain' => [ 'Tag' ],
'recursive' => - 1 ,
));
if ( ! $attributeTag ) {
throw new NotFoundException ( __ ( 'Invalid tag.' ));
}
$this -> set ( 'is_local' , $attributeTag [ 'AttributeTag' ][ 'local' ]);
$this -> set ( 'tag' , $attributeTag );
$this -> set ( 'id' , $attribute [ 'Attribute' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
$this -> set ( 'tag_id' , $tag_id );
$this -> set ( 'model' , 'Attribute' );
2020-08-15 15:49:17 +02:00
$this -> set ( 'model_name' , $attribute [ 'Attribute' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
$this -> render ( 'ajax/tagRemoveConfirmation' );
} else {
$rearrangeRules = array (
'request' => false ,
'Attribute' => false ,
'tag_id' => 'tag' ,
'attribute_id' => 'attribute' ,
'id' => 'attribute'
);
$RearrangeTool = new RequestRearrangeTool ();
$this -> request -> data = $RearrangeTool -> rearrangeArray ( $this -> request -> data , $rearrangeRules );
if ( $id === false ) {
2019-10-04 15:34:18 +02:00
if ( ! isset ( $this -> request -> data [ 'attribute' ])) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
2018-07-19 11:48:22 +02:00
$id = $this -> request -> data [ 'attribute' ];
}
if ( $tag_id === false ) {
2019-10-04 15:34:18 +02:00
if ( ! isset ( $this -> request -> data [ 'tag' ])) {
throw new NotFoundException ( __ ( 'Invalid tag' ));
}
2018-07-19 11:48:22 +02:00
$tag_id = $this -> request -> data [ 'tag' ];
}
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$this -> Attribute -> read ();
if ( $this -> Attribute -> data [ 'Attribute' ][ 'deleted' ]) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$eventId = $this -> Attribute -> data [ 'Attribute' ][ 'event_id' ];
if ( empty ( $tag_id )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Tag.' )), 'status' => 200 , 'type' => 'json' ));
}
if ( ! is_numeric ( $tag_id )) {
$tag = $this -> Attribute -> AttributeTag -> Tag -> find ( 'first' , array ( 'recursive' => - 1 , 'conditions' => array ( 'LOWER(Tag.name) LIKE' => strtolower ( trim ( $tag_id )))));
if ( empty ( $tag )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid Tag.' )), 'status' => 200 , 'type' => 'json' ));
}
$tag_id = $tag [ 'Tag' ][ 'id' ];
}
if ( ! is_numeric ( $id )) {
$id = $this -> request -> data [ 'Attribute' ][ 'id' ];
}
$this -> Attribute -> Event -> recursive = - 1 ;
$event = $this -> Attribute -> Event -> read ( array (), $eventId );
if ( ! $this -> _isRest ()) {
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $eventId );
}
$this -> Attribute -> recursive = - 1 ;
$attributeTag = $this -> Attribute -> AttributeTag -> find ( 'first' , array (
'conditions' => array (
'attribute_id' => $id ,
'tag_id' => $tag_id
),
'recursive' => - 1 ,
));
2019-07-08 11:39:41 +02:00
// org should allow to (un)tag too, so that an event that gets pushed can be (un)tagged locally by the owning org
2020-07-22 08:45:51 +02:00
if ( ! $this -> __canModifyTag ( $event , ! empty ( $attributeTag [ 'AttributeTag' ][ 'local' ]))) {
2019-08-14 14:33:20 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'You do not have permission to do that.' )), 'status' => 200 , 'type' => 'json' ));
2019-07-08 11:39:41 +02:00
}
2018-07-19 11:48:22 +02:00
$this -> autoRender = false ;
if ( empty ( $attributeTag )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Invalid attribute - tag combination.' )), 'status' => 200 , 'type' => 'json' ));
}
$tag = $this -> Attribute -> AttributeTag -> Tag -> find ( 'first' , array (
'conditions' => array ( 'Tag.id' => $tag_id ),
'recursive' => - 1 ,
'fields' => array ( 'Tag.name' )
));
if ( $this -> Attribute -> AttributeTag -> delete ( $attributeTag [ 'AttributeTag' ][ 'id' ])) {
2019-11-13 14:07:12 +01:00
if ( empty ( $attributeTag [ 'AttributeTag' ][ 'local' ])) {
$event [ 'Event' ][ 'published' ] = 0 ;
$date = new DateTime ();
$event [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> Event -> save ( $event );
2020-01-16 11:02:56 +01:00
if ( $this -> Attribute -> data [ 'Attribute' ][ 'object_id' ] != 0 ) {
$this -> Attribute -> Object -> updateTimestamp ( $this -> Attribute -> data [ 'Attribute' ][ 'object_id' ], $date -> getTimestamp ());
}
2019-11-13 14:07:12 +01:00
$this -> Attribute -> data [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> save ( $this -> Attribute -> data );
}
2018-07-19 11:48:22 +02:00
$log = ClassRegistry :: init ( 'Log' );
$log -> createLogEntry ( $this -> Auth -> user (), 'tag' , 'Attribute' , $id , 'Removed tag (' . $tag_id . ') "' . $tag [ 'Tag' ][ 'name' ] . '" from attribute (' . $id . ')' , 'Attribute (' . $id . ') untagged of Tag (' . $tag_id . ')' );
2021-04-15 11:10:11 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Tag removed.' , 'check_publish' => empty ( $attributeTag [ 'AttributeTag' ][ 'local' ]))), 'status' => 200 , 'type' => 'json' ));
2018-07-19 11:48:22 +02:00
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Tag could not be removed.' )), 'status' => 200 , 'type' => 'json' ));
}
}
}
public function toggleCorrelation ( $id )
{
2020-05-15 09:05:50 +02:00
if ( ! $this -> _isSiteAdmin () && ! Configure :: read ( 'MISP.allow_disabling_correlation' )) {
2018-07-19 11:48:22 +02:00
throw new MethodNotAllowedException ( __ ( 'Disabling the correlation is not permitted on this instance.' ));
}
$attribute = $this -> Attribute -> find ( 'first' , array (
2020-07-20 10:10:47 +02:00
'conditions' => array ( 'Attribute.id' => $id ),
2018-07-19 11:48:22 +02:00
'recursive' => - 1 ,
'contain' => array ( 'Event' )
));
if ( empty ( $attribute )) {
throw new NotFoundException ( __ ( 'Invalid Attribute.' ));
}
2020-07-20 10:10:47 +02:00
if ( ! $this -> __canModifyEvent ( $attribute )) {
throw new ForbiddenException ( __ ( 'You do not have permission to do that.' ));
2018-07-19 11:48:22 +02:00
}
if ( ! $this -> _isRest ()) {
$this -> Attribute -> Event -> insertLock ( $this -> Auth -> user (), $attribute [ 'Event' ][ 'id' ]);
}
if ( $this -> request -> is ( 'post' )) {
if ( $attribute [ 'Attribute' ][ 'disable_correlation' ]) {
$attribute [ 'Attribute' ][ 'disable_correlation' ] = 0 ;
} else {
$attribute [ 'Attribute' ][ 'disable_correlation' ] = 1 ;
}
2021-10-06 19:02:27 +02:00
$this -> Attribute -> save ( $attribute , [ 'parentEvent' => $attribute ]);
2018-07-19 11:48:22 +02:00
if ( $this -> _isRest ()) {
return $this -> RestResponse -> saveSuccessResponse ( 'attributes' , 'toggleCorrelation' , $id , false , 'Correlation ' . ( $attribute [ 'Attribute' ][ 'disable_correlation' ] ? 'disabled' : 'enabled' ) . '.' );
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => ( 'Correlation ' . ( $attribute [ 'Attribute' ][ 'disable_correlation' ] ? 'disabled' : 'enabled' )), 'check_publish' => true )), 'status' => 200 , 'type' => 'json' ));
}
} else {
$this -> set ( 'attribute' , $attribute );
$this -> render ( 'ajax/toggle_correlation' );
}
}
2019-02-26 16:24:01 +01:00
public function toggleToIDS ( $id )
{
return $this -> fetchEditForm ( $id , 'to_ids' );
}
2018-07-19 11:48:22 +02:00
public function checkAttachments ()
{
$attributes = $this -> Attribute -> find (
'all' ,
array (
'conditions' => array ( 'Attribute.type' => array ( 'attachment' , 'malware-sample' )),
2020-10-01 09:34:49 +02:00
'contain' => [ 'Event.orgc_id' , 'Event.org_id' ],
2020-10-01 09:26:46 +02:00
'recursive' => - 1
)
2018-07-19 11:48:22 +02:00
);
$counter = 0 ;
2020-05-05 15:23:26 +02:00
$attachmentTool = new AttachmentTool ();
2020-10-01 09:17:59 +02:00
$results = [];
2018-07-19 11:48:22 +02:00
foreach ( $attributes as $attribute ) {
2020-05-05 15:23:26 +02:00
$exists = $attachmentTool -> exists ( $attribute [ 'Attribute' ][ 'event_id' ], $attribute [ 'Attribute' ][ 'id' ]);
if ( ! $exists ) {
2020-10-01 09:17:59 +02:00
$results [ 'affectedEvents' ][ $attribute [ 'Attribute' ][ 'event_id' ]] = $attribute [ 'Attribute' ][ 'event_id' ];
2020-10-01 09:21:15 +02:00
$results [ 'affectedAttributes' ][] = $attribute [ 'Attribute' ][ 'id' ];
2020-10-01 09:26:46 +02:00
foreach ([ 'orgc' , 'org' ] as $type ) {
2020-10-01 09:34:49 +02:00
if ( empty ( $results [ 'affectedOrgs' ][ $type ][ $attribute [ 'Event' ][ $type . '_id' ]])) {
2020-10-01 09:28:33 +02:00
$results [ 'affectedOrgs' ][ $type ][ $attribute [ 'Event' ][ $type . '_id' ]] = 0 ;
2020-10-01 09:26:46 +02:00
} else {
2020-10-01 09:28:33 +02:00
$results [ 'affectedOrgs' ][ $type ][ $attribute [ 'Event' ][ $type . '_id' ]] += 1 ;
2020-10-01 09:26:46 +02:00
}
}
2018-07-19 11:48:22 +02:00
$counter ++ ;
}
}
2020-10-01 09:17:59 +02:00
if ( ! empty ( $results )) {
$results [ 'affectedEvents' ] = array_values ( $results [ 'affectedEvents' ]);
2020-10-01 09:21:15 +02:00
rsort ( $results [ 'affectedEvents' ]);
rsort ( $results [ 'affectedAttributes' ]);
2020-10-01 09:26:46 +02:00
foreach ([ 'orgc' , 'org' ] as $type ) {
arsort ( $results [ 'affectedOrgs' ][ $type ]);
}
2020-10-01 09:17:59 +02:00
}
file_put_contents ( APP . '/tmp/logs/missing_attachments.log' , json_encode ( $results , JSON_PRETTY_PRINT ));
2020-05-05 15:23:26 +02:00
return new CakeResponse ( array ( 'body' => $counter , 'status' => 200 ));
2018-07-19 11:48:22 +02:00
}
2018-10-04 22:24:35 +02:00
2018-11-23 14:11:33 +01:00
public function exportSearch ( $type = false )
{
if ( empty ( $type )) {
$exports = array_keys ( $this -> Attribute -> validFormats );
$this -> set ( 'exports' , $exports );
$this -> render ( 'ajax/exportSearch' );
} else {
$filters = $this -> Session -> read ( 'search_attributes_filters' );
$filters = json_decode ( $filters , true );
$final = $this -> Attribute -> restSearch ( $this -> Auth -> user (), $type , $filters );
$responseType = $this -> Attribute -> validFormats [ $type ][ 0 ];
return $this -> RestResponse -> viewData ( $final , $responseType , false , true , 'search.' . $type . '.' . $responseType );
}
}
2020-04-28 15:42:58 +02:00
2020-04-28 17:46:38 +02:00
private function __getInfo ()
2019-10-06 10:29:20 +02:00
{
$info = array ( 'category' => array (), 'type' => array (), 'distribution' => array ());
foreach ( $this -> Attribute -> categoryDefinitions as $key => $value ) {
$info [ 'category' ][ $key ] = array (
'key' => $key ,
'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]
);
}
foreach ( $this -> Attribute -> typeDefinitions as $key => $value ) {
$info [ 'type' ][ $key ] = array (
'key' => $key ,
'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]
);
}
foreach ( $this -> Attribute -> distributionLevels as $key => $value ) {
$info [ 'distribution' ][ $key ] = array (
'key' => $value ,
'desc' => $this -> Attribute -> distributionDescriptions [ $key ][ 'formdesc' ]
);
}
return $info ;
}
2020-07-20 10:10:47 +02:00
2020-08-06 11:52:53 +02:00
/**
* @ param int | string $id Attribute ID or UUID
* @ return array
*/
2020-07-20 10:10:47 +02:00
private function __fetchAttribute ( $id )
{
$options = array (
'conditions' => $this -> __idToConditions ( $id ),
'contain' => array (
'Event' ,
),
'withAttachments' => $this -> _isRest (),
'flatten' => true ,
'includeAllTags' => false ,
'includeAttributeUuid' => true ,
'limit' => 1 ,
);
$attributes = $this -> Attribute -> fetchAttributes ( $this -> Auth -> user (), $options );
if ( ! empty ( $attributes )) {
return $attributes [ 0 ];
} else {
return null ;
}
}
2020-08-06 11:52:53 +02:00
/**
* @ param int | string $id Attribute ID or UUID
* @ return array
*/
2020-07-20 10:10:47 +02:00
private function __idToConditions ( $id )
{
if ( is_numeric ( $id )) {
$conditions = array ( 'Attribute.id' => $id );
} elseif ( Validation :: uuid ( $id )) {
$conditions = array ( 'Attribute.uuid' => $id );
} else {
throw new NotFoundException ( __ ( 'Invalid attribute ID.' ));
}
return $conditions ;
}
2020-08-06 11:52:53 +02:00
/**
* @ param int $sharingGroupId
* @ return bool
*/
private function __canUseSharingGroup ( $sharingGroupId )
{
$sg = $this -> Attribute -> Event -> SharingGroup -> fetchAllAuthorised ( $this -> Auth -> user (), 'name' , true , $sharingGroupId );
return ! empty ( $sg );
}
2013-03-04 18:05:17 +01:00
}