2013-03-04 18:05:17 +01:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
App :: uses ( 'Folder' , 'Utility' );
App :: uses ( 'File' , 'Utility' );
/**
* Attributes Controller
*
* @ property Attribute $Attribute
*/
class AttributesController extends AppController {
2013-12-17 11:38:06 +01:00
public $components = array ( 'Security' , 'RequestHandler' , 'Cidr' );
2013-03-04 18:05:17 +01:00
public $paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 , // LATER we will bump here on a problem once we have more than 9999 events
);
public $helpers = array ( 'Js' => array ( 'Jquery' ));
public function beforeFilter () {
parent :: beforeFilter ();
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
$this -> Auth -> allow ( 'restSearch' );
$this -> Auth -> allow ( 'returnAttributes' );
2013-09-19 17:28:55 +02:00
$this -> Auth -> allow ( 'downloadAttachment' );
2014-03-24 16:33:40 +01:00
$this -> Auth -> allow ( 'text' );
2015-05-20 15:04:41 +02:00
$this -> Auth -> allow ( 'rpz' );
2013-03-04 18:05:17 +01:00
// permit reuse of CSRF tokens on the search page.
if ( 'search' == $this -> request -> params [ 'action' ]) {
$this -> Security -> csrfUseOnce = false ;
}
2013-04-25 14:04:08 +02:00
$this -> Security -> validatePost = true ;
2013-03-04 18:05:17 +01:00
// convert uuid to id if present in the url, and overwrite id field
if ( isset ( $this -> params -> query [ 'uuid' ])) {
$params = array (
'conditions' => array ( 'Attribute.uuid' => $this -> params -> query [ 'uuid' ]),
'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
}
}
2013-04-25 14:04:08 +02:00
// do not show private to other orgs
2013-04-17 11:13:09 +02:00
// if not admin or own org, check private as well..
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-04-17 11:13:09 +02:00
$this -> paginate = Set :: merge ( $this -> paginate , array (
'conditions' =>
array ( 'OR' =>
array (
'Event.org =' => $this -> Auth -> user ( 'org' ),
'AND' => array (
2013-06-10 23:34:47 +02:00
'Attribute.distribution >' => 0 ,
'Event.distribution >' => 0 ,
2015-02-05 17:16:40 +01:00
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published =' => 1 ) : array (),
2013-04-17 11:13:09 +02:00
)))));
2013-03-04 18:05:17 +01:00
}
2013-06-10 17:33:03 +02:00
/* We want to show this outside now as discussed with Christophe . Still not pushable , but anything should be pullable that ' s visible
2013-03-04 18:05:17 +01:00
// do not show cluster outside server
2013-04-17 11:13:09 +02:00
if ( $this -> _isRest ()) {
$this -> paginate = Set :: merge ( $this -> paginate , array (
'conditions' =>
array ( " AND " => array ( 'Event.cluster !=' => true ), array ( 'Attribute.cluster !=' => true )),
//array("AND" => array(array('Event.private !=' => 2))),
));
2013-03-04 18:05:17 +01:00
}
2013-06-10 17:33:03 +02:00
*/
2013-03-04 18:05:17 +01:00
}
/**
* index method
*
* @ return void
*
*/
public function index () {
$this -> Attribute -> recursive = 0 ;
2014-12-03 17:23:32 +01:00
$this -> Attribute -> contain = array ( 'Event.id' , 'Event.orgc' , 'Event.org' , 'Event.info' );
2013-03-04 18:05:17 +01:00
$this -> set ( 'isSearch' , 0 );
2013-04-25 15:37:49 +02:00
$this -> set ( 'attributes' , $this -> paginate ());
2013-03-04 18:05:17 +01:00
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
}
/**
* add method
*
* @ return void
*
* @ throws NotFoundException // TODO Exception
*/
public function add ( $eventId = null ) {
2014-02-28 12:00:16 +01:00
if ( ! $this -> userRole [ 'perm_add' ]) {
throw new MethodNotAllowedException ( 'You don\'t have permissions to create attributes' );
}
2014-05-02 14:29:15 +02:00
if ( $this -> request -> is ( 'ajax' )) {
$this -> set ( 'ajax' , true );
$this -> layout = 'ajax' ;
}
2014-03-24 16:33:40 +01:00
else $this -> set ( 'ajax' , false );
2013-03-04 18:05:17 +01:00
if ( $this -> request -> is ( 'post' )) {
2014-03-24 16:33:40 +01:00
if ( $this -> request -> is ( 'ajax' )) $this -> autoRender = false ;
2013-03-04 18:05:17 +01:00
$this -> loadModel ( 'Event' );
2013-06-06 14:55:13 +02:00
$date = new DateTime ();
2015-08-04 02:00:21 +02:00
2013-03-04 18:05:17 +01:00
// remove the published flag from the event
2013-06-06 14:55:13 +02:00
$this -> Event -> recursive = - 1 ;
2015-08-04 02:00:21 +02:00
if ( isset ( $eventId )) {
$this -> Event -> read ( null , $eventId );
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
} else $this -> Event -> read ( null , $this -> request -> data [ 'Attribute' ][ 'event_id' ]);
2013-08-12 17:23:32 +02:00
if ( ! $this -> _isSiteAdmin () && ( $this -> Event -> data [ 'Event' ][ 'orgc' ] != $this -> _checkOrg () || ! $this -> userRole [ 'perm_modify' ])) {
throw new UnauthorizedException ( 'You do not have permission to do that.' );
}
2013-06-06 14:55:13 +02:00
$this -> Event -> set ( 'timestamp' , $date -> getTimestamp ());
$this -> Event -> set ( 'published' , 0 );
$this -> Event -> save ( $this -> Event -> data , array ( 'fieldList' => array ( 'published' , 'timestamp' , 'info' )));
2015-09-07 10:06:34 +02:00
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'id' ])) unset ( $this -> request -> data [ 'Attribute' ][ 'id' ]);
2013-03-04 18:05:17 +01:00
//
// multiple attributes in batch import
//
if (( isset ( $this -> request -> data [ 'Attribute' ][ 'batch_import' ]) && $this -> request -> data [ 'Attribute' ][ 'batch_import' ] == 1 )) {
// make array from value field
$attributes = explode ( " \n " , $this -> request -> data [ 'Attribute' ][ 'value' ]);
$fails = " " ; // will be used to keep a list of the lines that failed or succeeded
$successes = " " ;
2014-05-02 14:29:15 +02:00
$failCount = 0 ;
$successCount = 0 ;
2013-03-04 18:05:17 +01:00
// TODO loop-holes,
// the value null value thing
foreach ( $attributes as $key => $attribute ) {
$attribute = trim ( $attribute );
if ( strlen ( $attribute ) == 0 )
continue ; // don't do anything for empty lines
$this -> Attribute -> create ();
2013-04-24 15:20:20 +02:00
$this -> request -> data [ 'Attribute' ][ 'value' ] = $attribute ; // set the value as the content of the single line
2013-03-04 18:05:17 +01:00
// TODO loop-holes,
// there seems to be a loop-hole in misp here
// be it an create and not an update
$this -> Attribute -> id = null ;
if ( $this -> Attribute -> save ( $this -> request -> data )) {
$successes .= " " . ( $key + 1 );
2014-05-02 14:29:15 +02:00
$successCount ++ ;
2013-03-04 18:05:17 +01:00
} else {
$fails .= " " . ( $key + 1 );
2014-05-02 14:29:15 +02:00
$failCount ++ ;
2013-03-04 18:05:17 +01:00
}
}
2014-04-16 15:52:25 +02:00
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
2014-04-24 15:10:08 +02:00
if ( $fails ) {
$error_message = 'The lines' . $fails . ' could not be saved. Please, try again.' ;
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => $error_message )), 'status' => 200 ));
2014-04-24 15:10:08 +02:00
} else {
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => $successCount . ' Attributes added' )), 'status' => 200 ));
2014-04-24 15:10:08 +02:00
}
2014-04-16 15:52:25 +02:00
} else {
// we added all the attributes,
if ( $fails ) {
// list the ones that failed
if ( ! CakeSession :: read ( 'Message.flash' )) {
$this -> Session -> setFlash ( __ ( 'The lines' . $fails . ' could not be saved. Please, try again.' , true ), 'default' , array (), 'error' );
} else {
$existingFlash = CakeSession :: read ( 'Message.flash' );
$this -> Session -> setFlash ( __ ( 'The lines' . $fails . ' could not be saved. ' . $existingFlash [ 'message' ], true ), 'default' , array (), 'error' );
}
2013-03-04 18:05:17 +01:00
}
2014-04-16 15:52:25 +02:00
if ( $successes ) {
// list the ones that succeeded
$this -> Session -> setFlash ( __ ( 'The lines' . $successes . ' have been saved' , true ));
}
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
2013-03-04 18:05:17 +01:00
}
} else {
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'uuid' ])) { // TODO here we should start RESTful dialog
2013-06-06 14:55:13 +02:00
// check if the uuid already exists and also save the existing attribute for further checks
$existingAttribute = null ;
$existingAttribute = $this -> Attribute -> find ( 'first' , array ( 'conditions' => array ( 'Attribute.uuid' => $this -> request -> data [ 'Attribute' ][ 'uuid' ])));
//$existingAttributeCount = $this->Attribute->find('count', array('conditions' => array('Attribute.uuid' => $this->request->data['Attribute']['uuid'])));
if ( $existingAttribute ) {
2013-03-04 18:05:17 +01:00
// TODO RESTfull, set responce location header..so client can find right URL to edit
2014-02-05 15:01:26 +01:00
$this -> response -> header ( 'Location' , Configure :: read ( 'MISP.baseurl' ) . '/attributes/' . $existingAttribute [ 'Attribute' ][ 'id' ]);
2013-03-04 18:05:17 +01:00
$this -> response -> send ();
2015-08-17 16:10:10 +02:00
throw new NotFoundException ( 'Attribute already exists, if you would like to edit it, use the url in the location header.' );
2013-06-06 14:55:13 +02:00
} else {
// if the attribute doesn't exist yet, check whether it has a timestamp - if yes, it's from a push, keep the timestamp we had, if no create a timestamp
if ( ! isset ( $this -> request -> data [ 'Attribute' ][ 'timestamp' ])) {
$this -> request -> data [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
}
}
} else {
if ( ! isset ( $this -> request -> data [ 'Attribute' ][ 'timestamp' ])) {
$this -> request -> data [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
2013-03-04 18:05:17 +01:00
}
}
2015-08-04 02:00:21 +02:00
if ( isset ( $this -> request -> data [ 'Attribute' ][ 'base64' ])) $this -> request -> data [ 'Attribute' ][ 'data' ] = $this -> request -> data [ 'Attribute' ][ 'base64' ];
2013-03-04 18:05:17 +01:00
//
// single attribute
//
// create the attribute
$this -> Attribute -> create ();
2015-04-14 13:50:51 +02:00
$savedId = $this -> Attribute -> getID ();
2013-03-04 18:05:17 +01:00
if ( $this -> Attribute -> save ( $this -> request -> data )) {
2015-04-14 13:50:51 +02:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
$saved_attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'id' => $this -> Attribute -> id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'type' , 'to_ids' , 'category' , 'uuid' , 'event_id' , 'distribution' , 'timestamp' , 'comment' , 'value' ),
));
$response = array ( 'response' => array ( 'Attribute' => $saved_attribute [ 'Attribute' ]));
$this -> set ( 'response' , $response );
if ( $this -> response -> type () === 'application/json' ) $this -> render ( '/Attributes/json/view' );
else $this -> render ( 'view' );
return false ;
2014-03-24 16:33:40 +01:00
} elseif ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Attribute added.' )), 'status' => 200 ));
2013-03-04 18:05:17 +01:00
} else {
// inform the user and redirect
$this -> Session -> setFlash ( __ ( 'The attribute has been saved' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
} else {
if ( $this -> _isRest ()) { // TODO return error if REST
// REST users want to see the failed attribute
2015-08-17 16:10:10 +02:00
throw new NotFoundException ( 'Could not save the attribute. ' . $this -> Attribute -> validationErrors );
2014-03-24 16:33:40 +01:00
} elseif ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
2014-04-24 15:10:08 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $this -> Attribute -> validationErrors )), 'status' => 200 ));
2013-03-04 18:05:17 +01:00
} else {
if ( ! CakeSession :: read ( 'Message.flash' )) {
$this -> Session -> setFlash ( __ ( 'The attribute could not be saved. Please, try again.' ));
}
}
}
}
} else {
// set the event_id in the form
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
}
// combobox for types
$types = array_keys ( $this -> Attribute -> typeDefinitions );
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobos for categories
$categories = $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ];
array_pop ( $categories );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
$this -> set ( 'categories' , compact ( 'categories' ));
$this -> loadModel ( 'Event' );
$events = $this -> Event -> findById ( $eventId );
2014-03-24 16:33:40 +01:00
$this -> set ( 'event_id' , $events [ 'Event' ][ 'id' ]);
2013-03-04 18:05:17 +01:00
// combobox for distribution
2013-06-11 01:20:27 +02:00
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
2013-07-15 09:10:18 +02:00
$this -> set ( 'currentDist' , $events [ 'Event' ][ 'distribution' ]); // TODO default distribution
2013-03-04 18:05:17 +01:00
// tooltip for distribution
$this -> set ( 'distributionDescriptions' , $this -> Attribute -> distributionDescriptions );
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
2013-06-26 17:20:56 +02:00
$this -> set ( 'published' , $events [ 'Event' ][ 'published' ]);
2013-03-04 18:05:17 +01:00
}
public function download ( $id = null ) {
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$this -> Attribute -> read ();
2013-11-12 16:23:37 +01:00
if ( ! $this -> _isSiteAdmin () &&
$this -> Auth -> user ( 'org' ) !=
$this -> Attribute -> data [ 'Event' ][ 'org' ] &&
( $this -> Attribute -> data [ 'Event' ][ 'distribution' ] == 0 ||
2013-09-19 17:28:55 +02:00
$this -> Attribute -> data [ 'Attribute' ][ 'distribution' ] == 0
)) {
throw new UnauthorizedException ( 'You do not have the permission to view this event.' );
}
$this -> __downloadAttachment ( $this -> Attribute -> data [ 'Attribute' ]);
}
2013-10-15 10:35:08 +02:00
2013-09-19 17:28:55 +02:00
private function __downloadAttachment ( $attribute ) {
$path = " files " . DS . $attribute [ 'event_id' ] . DS ;
$file = $attribute [ 'id' ];
2013-03-04 18:05:17 +01:00
$filename = '' ;
2013-09-19 17:28:55 +02:00
if ( 'attachment' == $attribute [ 'type' ]) {
$filename = $attribute [ 'value' ];
2013-03-04 18:05:17 +01:00
$fileExt = pathinfo ( $filename , PATHINFO_EXTENSION );
$filename = substr ( $filename , 0 , strlen ( $filename ) - strlen ( $fileExt ) - 1 );
2013-09-19 17:28:55 +02:00
} elseif ( 'malware-sample' == $attribute [ 'type' ]) {
$filenameHash = explode ( '|' , $attribute [ 'value' ]);
2013-03-04 18:05:17 +01:00
$filename = $filenameHash [ 0 ];
$filename = substr ( $filenameHash [ 0 ], strrpos ( $filenameHash [ 0 ], '\\' ));
$fileExt = " zip " ;
} else {
throw new NotFoundException ( __ ( 'Attribute not an attachment or malware-sample' ));
}
2013-07-10 17:31:18 +02:00
$this -> autoRender = false ;
$this -> response -> type ( $fileExt );
$this -> response -> file ( $path . $file , array ( 'download' => true , 'name' => $filename . '.' . $fileExt ));
2013-03-04 18:05:17 +01:00
}
2015-08-04 02:00:21 +02:00
/**
* add_attachment method
*
* @ return void
* @ throws InternalErrorException
*/
2013-03-04 18:05:17 +01:00
public function add_attachment ( $eventId = null ) {
if ( $this -> request -> is ( 'post' )) {
2015-08-04 02:00:21 +02:00
$hashes = array ( 'md5' => 'malware-sample' , 'sha1' => 'filename|sha1' , 'sha256' => 'filename|sha256' );
2013-03-04 18:05:17 +01:00
$this -> loadModel ( 'Event' );
2013-08-12 17:23:32 +02:00
$this -> Event -> id = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
$this -> Event -> recursive = - 1 ;
$this -> Event -> read ();
if ( ! $this -> _isSiteAdmin () && ( $this -> Event -> data [ 'Event' ][ 'orgc' ] != $this -> _checkOrg () || ! $this -> userRole [ 'perm_modify' ])) {
throw new UnauthorizedException ( 'You do not have permission to do that.' );
}
2013-03-04 18:05:17 +01: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 ( $this -> request -> data [ 'Attribute' ][ 'value' ][ 'name' ]);
$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 ) ||
2015-08-04 02:00:21 +02:00
( ! empty ( $this -> request -> data [ 'Attribute' ][ 'value' ][ 'tmp_name' ]) && $this -> request -> data [ 'Attribute' ][ 'value' ][ 'tmp_name' ] != 'none' )
2013-03-04 18:05:17 +01:00
) {
if ( ! is_uploaded_file ( $tmpfile -> path ))
throw new InternalErrorException ( 'PHP says file was not uploaded. Are you attacking me?' );
} else {
$this -> Session -> setFlash ( __ ( 'There was a problem to upload the file.' , true ), 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
2015-08-04 02:00:21 +02:00
$fails = array ();
$completeFail = false ;
2013-03-04 18:05:17 +01:00
if ( $this -> request -> data [ 'Attribute' ][ 'malware' ]) {
2015-08-04 02:00:21 +02:00
$result = $this -> Event -> Attribute -> handleMaliciousBase64 ( $this -> request -> data [ 'Attribute' ][ 'event_id' ], $filename , base64_encode ( $tmpfile -> read ()), array_keys ( $hashes ));
if ( ! $result [ 'success' ]) {
$this -> Session -> setFlash ( __ ( 'There was a problem to upload the file.' , true ), 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
}
foreach ( $hashes as $hash => $typeName ) {
if ( ! $result [ $hash ]) continue ;
$attribute = array (
'Attribute' => array (
'value' => $filename . '|' . $result [ $hash ],
'category' => $this -> request -> data [ 'Attribute' ][ 'category' ],
'type' => $typeName ,
'event_id' => $this -> request -> data [ 'Attribute' ][ 'event_id' ],
2015-08-27 09:44:58 +02:00
'to_ids' => 1 ,
'distribution' => $this -> request -> data [ 'Attribute' ][ 'distribution' ],
2015-08-04 02:00:21 +02:00
)
);
if ( $hash == 'md5' ) $attribute [ 'Attribute' ][ 'data' ] = $result [ 'data' ];
$this -> Attribute -> create ();
$r = $this -> Attribute -> save ( $attribute );
if ( $r == false ) $fails [] = array ( $typeName );
if ( count ( $fails ) == count ( $hashes )) $completeFail = true ;
}
2013-03-04 18:05:17 +01:00
} else {
2015-08-04 02:00:21 +02:00
$attribute = array (
'Attribute' => array (
'value' => $filename ,
'category' => $this -> request -> data [ 'Attribute' ][ 'category' ],
'type' => 'attachment' ,
'event_id' => $this -> request -> data [ 'Attribute' ][ 'event_id' ],
'data' => base64_encode ( $tmpfile -> read ()),
2015-08-27 09:44:58 +02:00
'to_ids' => 0 ,
'distribution' => $this -> request -> data [ 'Attribute' ][ 'distribution' ],
2015-08-04 02:00:21 +02:00
)
);
$this -> Attribute -> create ();
$r = $this -> Attribute -> save ( $attribute );
if ( $r == false ) {
$fails [] = array ( 'attachment' );
$completeFail = true ;
}
2013-03-04 18:05:17 +01:00
}
2015-08-04 02:00:21 +02:00
if ( ! $completeFail ) {
// attribute(s) saved correctly in the db
2013-07-15 09:10:18 +02:00
// remove the published flag from the event
2015-08-04 02:00:21 +02:00
if ( empty ( $fails )) $this -> Session -> setFlash ( __ ( 'The attachment has been uploaded' ));
else $this -> Session -> setFlash ( __ ( 'The attachment has been uploaded, but some of the attributes could not be created. The failed attributes are: ' . implode ( ', ' , $fails )));
2013-07-15 09:10:18 +02:00
$this -> Event -> id = $this -> request -> data [ 'Attribute' ][ 'event_id' ];
$this -> Event -> saveField ( 'published' , 0 );
2013-03-04 18:05:17 +01:00
} else {
2015-08-04 02:00:21 +02:00
$this -> Session -> setFlash ( __ ( 'The attachment could not be saved, please contact your administrator.' ));
2013-03-04 18:05:17 +01:00
}
2015-08-04 02:00:21 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'Attribute' ][ 'event_id' ]));
2013-03-04 18:05:17 +01:00
} else {
// set the event_id in the form
$this -> request -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
}
2015-08-04 02:00:21 +02:00
2013-03-04 18:05:17 +01:00
// combobos for categories
$categories = $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ];
// just get them with attachments..
$selectedCategories = array ();
foreach ( $categories as $category ) {
if ( isset ( $this -> Attribute -> categoryDefinitions [ $category ])) {
$types = $this -> Attribute -> categoryDefinitions [ $category ][ 'types' ];
$alreadySet = false ;
foreach ( $types as $type ) {
if ( $this -> Attribute -> typeIsAttachment ( $type ) && ! $alreadySet ) {
// add to the whole..
$selectedCategories [] = $category ;
$alreadySet = true ;
continue ;
}
}
}
};
$categories = $this -> _arrayToValuesIndexArray ( $selectedCategories );
$this -> set ( 'categories' , $categories );
2015-08-04 02:00:21 +02:00
2013-03-04 18:05:17 +01:00
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
2015-08-04 02:00:21 +02:00
2013-03-04 18:05:17 +01:00
$this -> set ( 'zippedDefinitions' , $this -> Attribute -> zippedDefinitions );
$this -> set ( 'uploadDefinitions' , $this -> Attribute -> uploadDefinitions );
2015-08-04 02:00:21 +02:00
2013-03-04 18:05:17 +01:00
// combobox for distribution
2013-07-15 09:10:18 +02:00
$this -> loadModel ( 'Event' );
2013-03-04 18:05:17 +01:00
$this -> set ( 'distributionDescriptions' , $this -> Attribute -> distributionDescriptions );
2013-06-10 20:49:31 +02:00
$this -> set ( 'distributionLevels' , $this -> Event -> distributionLevels );
2013-06-11 14:52:54 +02:00
$events = $this -> Event -> findById ( $eventId );
2013-06-11 01:20:27 +02:00
$this -> set ( 'currentDist' , $events [ 'Event' ][ 'distribution' ]);
2013-06-26 17:20:56 +02:00
$this -> set ( 'published' , $events [ 'Event' ][ 'published' ]);
2013-03-04 18:05:17 +01:00
}
2015-08-04 02:00:21 +02:00
2013-07-15 09:10:18 +02:00
/**
* Imports the CSV threatConnect file to multiple attributes
* @ param int $id The id of the event
*/
public function add_threatconnect ( $eventId = null ) {
if ( $this -> request -> is ( 'post' )) {
2013-08-12 17:23:32 +02:00
$this -> loadModel ( 'Event' );
$this -> Event -> id = $eventId ;
$this -> Event -> recursive = - 1 ;
$this -> Event -> read ();
if ( ! $this -> _isSiteAdmin () && ( $this -> Event -> data [ 'Event' ][ 'orgc' ] != $this -> _checkOrg () || ! $this -> userRole [ 'perm_modify' ])) {
throw new UnauthorizedException ( 'You do not have permission to do that.' );
}
2013-07-15 09:10:18 +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 -> Session -> setFlash ( __ ( '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 -> Session -> setFlash ( '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)
2014-02-14 11:09:04 +01:00
$required_headers = array ( 'Type' , 'Value' , 'Confidence' , 'Description' , 'Source' );
if ( count ( array_intersect ( $header , $required_headers )) != count ( $required_headers )) {
$this -> Session -> setFlash ( 'Incorrect ThreatConnect headers. The minimum required headers are: ' . implode ( ',' , $required_headers ), 'default' , array (), 'error' );
2013-07-15 09:10:18 +02:00
$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
2013-11-04 10:11:58 +01:00
$attribute [ 'comment' ] = 'ThreatConnect: ' . $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' );
2013-11-12 16:23:37 +01:00
}
2013-11-04 10:11:58 +01:00
}
2013-07-15 09:10:18 +02:00
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' ;
else if ( preg_match ( " #^[0-9a-f] { 40} $ # " , $attribute [ 'value' ]))
$attribute [ 'type' ] = 'sha1' ;
else if ( 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'
// else 'comment'
$references = array ();
foreach ( $entries as $entry ) {
$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
//
$this -> Attribute -> saveMany ( $attributes , array ( 'validate' => true ));
// 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
$this -> Session -> setFlash ( __ ( 'The ThreatConnect data has been imported' ));
$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' ]);
}
2013-03-04 18:05:17 +01:00
/**
* edit method
*
* @ param string $id
* @ return void
* @ throws NotFoundException
*/
public function edit ( $id = null ) {
$this -> Attribute -> id = $id ;
2013-06-06 16:03:28 +02:00
$date = new DateTime ();
2013-03-04 18:05:17 +01:00
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$this -> Attribute -> read ();
//set stuff to fix undefined index: uuid
if ( ! $this -> _isRest ()) {
$uuid = $this -> Attribute -> data [ 'Attribute' ][ 'uuid' ];
}
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-11-12 16:23:37 +01:00
//
2013-08-12 17:23:32 +02:00
if ( $this -> Attribute -> data [ 'Event' ][ 'orgc' ] == $this -> Auth -> user ( 'org' )
2013-11-12 16:23:37 +01:00
&& (( $this -> userRole [ 'perm_modify' ] && $this -> Attribute -> data [ 'Event' ][ 'user_id' ] != $this -> Auth -> user ( 'id' ))
2013-08-12 17:23:32 +02:00
|| $this -> userRole [ 'perm_modify_org' ])) {
// Allow the edit
} else {
2013-04-17 11:13:09 +02:00
$this -> Session -> setFlash ( __ ( 'Invalid attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
2013-03-04 18:05:17 +01:00
}
}
$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 );
// TODO we should ensure 'value' cannot be changed here and not only on a view level (because of the associated file)
// $this->Session->setFlash(__('You cannot edit attachment attributes.', true), 'default', array(), 'error');
// $this->redirect(array('controller' => 'events', 'action' => 'view', $old_attribute['Event']['id']));
} else {
$this -> set ( 'attachment' , false );
}
if ( $this -> request -> is ( 'post' ) || $this -> request -> is ( 'put' )) {
// reposition to get the attribute.id with given uuid
// Notice (8): Undefined index: uuid [APP/Controller/AttributesController.php, line 502]
// Fixed - uuid was not passed back from the form since it's not a field. Set the uuid in a variable for non rest users, rest should have uuid.
// Generally all of this should be _isRest() only, but that's something for later to think about
2015-04-14 13:50:51 +02:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
2013-03-04 18:05:17 +01:00
$existingAttribute = $this -> Attribute -> findByUuid ( $this -> request -> data [ 'Attribute' ][ 'uuid' ]);
} else {
$existingAttribute = $this -> Attribute -> findByUuid ( $uuid );
}
2015-09-07 14:25:24 +02:00
// 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
2013-03-04 18:05:17 +01:00
if ( count ( $existingAttribute )) {
$this -> request -> data [ 'Attribute' ][ 'id' ] = $existingAttribute [ 'Attribute' ][ 'id' ];
2015-09-07 14:25:24 +02:00
$dateObj = new DateTime ();
if ( ! isset ( $this -> request -> data [ 'Attribute' ][ 'timestamp' ])) $this -> request -> data [ 'Attribute' ][ 'timestamp' ] = $dateObj -> getTimestamp ();
if ( $this -> request -> data [ 'Attribute' ][ 'timestamp' ] > $existingAttribute [ 'Attribute' ][ 'timestamp' ]) {
$recoverFields = array ( 'value' , 'to_ids' , 'distribution' , 'category' , 'type' , 'comment' );
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.' );
2013-06-06 14:55:13 +02:00
}
2013-06-06 16:03:28 +02:00
} else {
2015-09-07 14:25:24 +02:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
throw new NotFoundException ( 'Invalid attribute.' );
} else {
$this -> Session -> setFlash ( __ ( 'Invalid attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
}
2013-06-06 14:55:13 +02:00
}
2013-10-30 16:00:46 +01:00
$fieldList = array ( 'category' , 'type' , 'value1' , 'value2' , 'to_ids' , 'distribution' , 'value' , 'timestamp' , 'comment' );
2013-03-04 18:05:17 +01:00
$this -> loadModel ( 'Event' );
$this -> Event -> id = $eventId ;
// enabling / disabling the distribution field in the edit view based on whether user's org == orgc in the event
$this -> Event -> read ();
if ( $this -> Attribute -> save ( $this -> request -> data )) {
$this -> Session -> setFlash ( __ ( 'The attribute has been saved' ));
// remove the published flag from the event
2013-06-06 16:03:28 +02:00
$this -> Event -> set ( 'timestamp' , $date -> getTimestamp ());
$this -> Event -> set ( 'published' , 0 );
$this -> Event -> save ( $this -> Event -> data , array ( 'fieldList' => array ( 'published' , 'timestamp' , 'info' )));
2015-04-14 13:50:51 +02:00
if ( $this -> _isRest () || $this -> response -> type () === 'application/json' ) {
$saved_attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'id' => $this -> Attribute -> id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'type' , 'to_ids' , 'category' , 'uuid' , 'event_id' , 'distribution' , 'timestamp' , 'comment' , 'value' ),
));
$response = array ( 'response' => array ( 'Attribute' => $saved_attribute [ 'Attribute' ]));
$this -> set ( 'response' , $response );
if ( $this -> response -> type () === 'application/json' ) $this -> render ( '/Attributes/json/view' );
else $this -> render ( 'view' );
return false ;
2013-03-04 18:05:17 +01:00
} else {
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $eventId ));
}
} else {
if ( ! CakeSession :: read ( 'Message.flash' )) {
$this -> Session -> setFlash ( __ ( 'The attribute could not be saved. Please, try again.' ));
} else {
$this -> request -> data = $this -> Attribute -> read ( null , $id );
}
}
} else {
$this -> request -> data = $this -> Attribute -> read ( null , $id );
}
2013-04-24 15:20:20 +02:00
$this -> set ( 'attribute' , $this -> request -> data );
2013-03-04 18:05:17 +01:00
// enabling / disabling the distribution field in the edit view based on whether user's org == orgc in the event
$this -> loadModel ( 'Event' );
$this -> Event -> id = $eventId ;
$this -> Event -> read ();
2013-10-24 10:33:34 +02:00
$this -> set ( 'published' , $this -> Event -> data [ 'Event' ][ 'published' ]);
2013-03-04 18:05:17 +01:00
// needed for RBAC
// combobox for types
$types = array_keys ( $this -> Attribute -> typeDefinitions );
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ];
array_pop ( $categories ); // remove that last empty/space option
$categories = $this -> _arrayToValuesIndexArray ( $categories );
$this -> set ( 'categories' , $categories );
2013-06-11 01:20:27 +02:00
$this -> set ( 'currentDist' , $this -> Event -> data [ 'Event' ][ 'distribution' ]);
2013-06-06 18:43:26 +02:00
// combobox for distribution
2013-06-11 01:20:27 +02:00
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
2013-06-06 18:43:26 +02:00
// tooltip for distribution
$this -> set ( 'distributionDescriptions' , $this -> Attribute -> distributionDescriptions );
2013-03-04 18:05:17 +01:00
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
}
2014-04-14 15:13:01 +02:00
// 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 ) {
if (( ! $this -> request -> is ( 'post' ) && ! $this -> request -> is ( 'put' )) || ! $this -> request -> is ( 'ajax' )) throw new MethodNotAllowedException ();
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'fail' => false , 'errors' => 'Invalid attribute' )), 'status' => 200 ));
2014-04-14 15:13:01 +02:00
}
$this -> Attribute -> recursive = - 1 ;
$this -> Attribute -> contain ( 'Event' );
$attribute = $this -> Attribute -> read ();
if ( ! $this -> _isSiteAdmin ()) {
//
if ( $this -> Attribute -> data [ 'Event' ][ 'orgc' ] == $this -> Auth -> user ( 'org' )
&& (( $this -> userRole [ 'perm_modify' ] && $this -> Attribute -> data [ 'Event' ][ 'user_id' ] != $this -> Auth -> user ( 'id' ))
|| $this -> userRole [ 'perm_modify_org' ])) {
// Allow the edit
} else {
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'fail' => false , 'errors' => 'Invalid attribute' )), 'status' => 200 ));
2014-04-14 15:13:01 +02:00
}
}
foreach ( $this -> request -> data [ 'Attribute' ] as $changedKey => $changedField ) {
if ( $attribute [ 'Attribute' ][ $changedKey ] == $changedField ) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( 'nochange' ), 'status' => 200 ));
}
$attribute [ 'Attribute' ][ $changedKey ] = $changedField ;
}
$date = new DateTime ();
$attribute [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
if ( $this -> Attribute -> save ( $attribute )) {
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'recursive' => - 1 ,
'fields' => array ( 'id' , 'published' , 'timestamp' , 'info' ),
'conditions' => array (
'id' => $attribute [ 'Attribute' ][ 'event_id' ],
)));
$event [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
$event [ 'Event' ][ 'published' ] = 0 ;
2014-05-02 14:29:15 +02:00
$this -> Attribute -> Event -> save ( $event , array ( 'fieldList' => array ( 'published' , 'timestamp' , 'info' )));
2014-04-14 15:13:01 +02:00
$this -> autoRender = false ;
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Field updated.' )), 'status' => 200 ));
2014-04-14 15:13:01 +02:00
} else {
$this -> autoRender = false ;
2014-05-02 14:29:15 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $this -> Attribute -> validationErrors )), 'status' => 200 ));
2014-04-14 15:13:01 +02:00
}
}
2015-04-14 13:50:51 +02:00
public function view ( $id , $hasChildren = 0 , $response = 'ajax' ) {
2014-04-14 15:13:01 +02:00
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( 'Invalid attribute' );
}
$this -> Attribute -> recursive = - 1 ;
$this -> Attribute -> contain ( 'Event' );
$attribute = $this -> Attribute -> read ();
if ( ! $this -> _isSiteAdmin ()) {
//
if ( $this -> Attribute -> data [ 'Event' ][ 'org' ] == $this -> Auth -> user ( 'org' ) || (( $this -> Attribute -> data [ 'Event' ][ 'distribution' ] > 0 ) && $this -> Attribute -> data [ 'Attribute' ][ 'distribution' ] > 0 )) {
throw new MethodNotAllowed ( 'Invalid attribute' );
}
}
2015-04-14 13:50:51 +02:00
if ( $this -> request -> is ( 'ajax' )) {
$eventRelations = $this -> Attribute -> Event -> getRelatedAttributes ( $this -> Auth -> user (), $this -> _isSiteAdmin (), $attribute [ 'Attribute' ][ 'event_id' ]);
$attribute [ 'Attribute' ][ 'relations' ] = array ();
if ( isset ( $eventRelations [ $id ])) {
foreach ( $eventRelations [ $id ] as $relations ) {
$attribute [ 'Attribute' ][ 'relations' ][] = array ( $relations [ 'id' ], $relations [ 'info' ], $relations [ 'org' ]);
}
2014-04-14 15:13:01 +02:00
}
2015-04-14 13:50:51 +02:00
$object = $attribute [ 'Attribute' ];
$object [ 'objectType' ] = 0 ;
$object [ 'hasChildren' ] = $hasChildren ;
$this -> set ( 'object' , $object );
$this -> set ( 'distributionLevels' , $this -> Attribute -> Event -> distributionLevels );
} else {
$this -> redirect ( '/events/view/' . $this -> Attribute -> data [ 'Attribute' ][ 'event_id' ]);
2014-04-14 15:13:01 +02:00
}
/*
$this -> autoRender = false ;
$responseObject = array ();
return new CakeResponse ( array ( 'body' => json_encode ( $attribute [ 'Attribute' ]), 'status' => 200 ));
*/
}
2013-03-04 18:05:17 +01:00
/**
* delete method
*
* @ param string $id
* @ return void
* @ throws MethodNotAllowedException
* @ throws NotFoundException
*
* and is able to delete w / o question
*/
public function delete ( $id = null ) {
2014-05-02 14:29:15 +02:00
if ( $this -> request -> is ( 'ajax' )) {
2014-05-07 17:16:19 +02:00
if ( $this -> request -> is ( 'post' )) {
if ( $this -> __delete ( $id )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Attribute deleted.' )), 'status' => 200 ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => 'Attribute was not deleted.' )), 'status' => 200 ));
}
2014-05-02 14:29:15 +02:00
} else {
2014-05-07 17:16:19 +02:00
$this -> set ( 'id' , $id );
2014-05-09 23:12:51 +02:00
$attribute = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'event_id' ),
));
$this -> set ( 'event_id' , $attribute [ 'Attribute' ][ 'event_id' ]);
$this -> render ( 'ajax/attributeConfirmationForm' );
2014-05-02 14:29:15 +02:00
}
2014-04-16 15:52:25 +02:00
} else {
2014-05-07 17:16:19 +02:00
if ( ! $this -> request -> is ( 'post' ) && ! $this -> _isRest ()) {
throw new MethodNotAllowedException ();
}
2014-05-02 14:29:15 +02:00
if ( $this -> __delete ( $id )) {
$this -> Session -> setFlash ( __ ( 'Attribute deleted' ));
} else {
$this -> Session -> setFlash ( __ ( 'Attribute was not deleted' ));
}
if ( ! $this -> _isRest ()) $this -> redirect ( $this -> referer ()); // TODO check
else $this -> redirect ( array ( 'action' => 'index' ));
2014-04-16 15:52:25 +02:00
}
}
/**
* unification of the actual delete for the multi - select
*
* @ param unknown $id
* @ throws NotFoundException
* @ throws MethodNotAllowedException
* @ return boolean
*
* returns true / false based on success
*/
private function __delete ( $id ) {
2013-03-04 18:05:17 +01:00
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
2014-05-02 14:29:15 +02:00
return false ;
2013-03-04 18:05:17 +01:00
}
2014-07-08 11:31:23 +02:00
$result = $this -> Attribute -> find ( 'first' , array (
'conditions' => array ( 'Attribute.id' => $id ),
'fields' => array ( 'Attribute.id, Attribute.event_id' , 'Attribute.uuid' ),
'contain' => array ( 'Event' => array (
'fields' => array ( 'Event.id' , 'Event.orgc' , 'Event.org' , 'Event.locked' )
)),
));
2014-09-10 09:43:22 +02:00
// find the uuid
$uuid = $result [ 'Attribute' ][ 'uuid' ];
2014-04-16 15:52:25 +02:00
2013-08-12 17:23:32 +02:00
// check for permissions
if ( ! $this -> _isSiteAdmin ()) {
2014-07-08 11:31:23 +02:00
if ( $result [ 'Event' ][ 'locked' ]) {
if ( $this -> _checkOrg () != $result [ 'Event' ][ 'org' ] || ! $this -> userRole [ 'perm_sync' ]) {
2013-08-12 17:23:32 +02:00
throw new MethodNotAllowedException ();
}
} else {
2014-07-08 11:31:23 +02:00
if ( $this -> _checkOrg () != $result [ 'Event' ][ 'orgc' ]) {
2013-08-12 17:23:32 +02:00
throw new MethodNotAllowedException ();
2013-11-12 16:23:37 +01:00
}
2013-08-12 17:23:32 +02:00
}
}
2014-04-16 15:52:25 +02:00
2013-03-04 18:05:17 +01:00
// attachment will be deleted with the beforeDelete() function in the Model
if ( $this -> Attribute -> delete ()) {
// delete the attribute from remote servers
2014-12-19 15:01:14 +01:00
//$this->__deleteAttributeFromServers($uuid);
2014-04-16 15:52:25 +02:00
2013-09-04 08:52:30 +02:00
// We have just deleted the attribute, let's also check if there are any shadow attributes that were attached to it and delete them
$this -> loadModel ( 'ShadowAttribute' );
$this -> ShadowAttribute -> deleteAll ( array ( 'ShadowAttribute.old_id' => $id ), false );
2014-04-16 15:52:25 +02:00
return true ;
2013-03-04 18:05:17 +01:00
} else {
2014-04-16 15:52:25 +02:00
return false ;
2013-03-04 18:05:17 +01:00
}
2014-04-16 15:52:25 +02:00
}
2014-04-24 15:10:08 +02:00
public function deleteSelected ( $id ) {
if ( ! $this -> request -> is ( 'post' ) && ! $this -> request -> is ( 'ajax' )) {
//if (!$this->request->is('post')) {
2014-04-16 15:52:25 +02:00
throw new MethodNotAllowedException ();
}
// 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.
2015-06-25 11:51:36 +02:00
$ids = json_decode ( $this -> request -> data [ 'Attribute' ][ 'ids_delete' ]);
2014-04-24 15:10:08 +02:00
if ( ! $this -> _isSiteAdmin ()) {
$event = $this -> Attribute -> Event -> find ( 'first' , array (
2014-05-07 17:16:19 +02:00
'conditions' => array ( 'id' => $id ),
2014-04-24 15:10:08 +02:00
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc' , 'user_id' )
));
if ( $event [ 'Event' ][ 'orgc' ] != $this -> Auth -> user ( 'org' ) || ( ! $this -> userRole [ 'perm_modify_org' ] && ! ( $this -> userRole [ 'perm_modify' ] && $event [ 'Event' ][ 'user_id' ] == $this -> Auth -> user ( 'id' )))) {
throw new MethodNotAllowedException ( 'Invalid Event.' );
}
}
// find all attributes from the ID list that also match the provided event ID.
$attributes = $this -> Attribute -> find ( 'all' , array (
'recursive' => - 1 ,
'conditions' => array ( 'id' => $ids , 'event_id' => $id ),
'fields' => array ( 'id' , 'event_id' )
));
2014-05-02 14:29:15 +02:00
$successes = array ();
2014-04-24 15:10:08 +02:00
foreach ( $attributes as $a ) {
2014-05-02 14:29:15 +02:00
if ( $this -> __delete ( $a [ 'Attribute' ][ 'id' ])) $successes [] = $a [ 'Attribute' ][ 'id' ];
2014-04-16 15:52:25 +02:00
}
2014-05-02 14:29:15 +02:00
$fails = array_diff ( $ids , $successes );
2014-04-16 15:52:25 +02:00
$this -> autoRender = false ;
2014-05-02 14:29:15 +02:00
if ( count ( $fails ) == 0 && count ( $successes ) > 0 ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => count ( $successes ) . ' attribute' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted.' )), 'status' => 200 ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => count ( $successes ) . ' attribute' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted, but ' . count ( $fails ) . ' attribute' . ( count ( $fails ) != 1 ? 's' : '' ) . ' could not be deleted.' )), 'status' => 200 ));
}
2014-04-24 15:10:08 +02:00
}
public function editSelected ( $id ) {
if ( ! $this -> request -> is ( 'ajax' )) throw new MethodNotAllowedException ( 'This method can only be accessed via AJAX.' );
if ( $this -> request -> is ( 'post' )) {
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc' , 'user_id' )
));
if ( ! $this -> _isSiteAdmin ()) {
2014-05-07 17:16:19 +02:00
if ( $event [ 'Event' ][ 'orgc' ] != $this -> Auth -> user ( 'org' ) || ( ! $this -> userRole [ 'perm_modify_org' ] && ! ( $this -> userRole [ 'perm_modify' ] && $event [ 'user_id' ] == $this -> Auth -> user ( 'id' )))) {
2014-04-24 15:10:08 +02:00
throw new MethodNotAllowedException ( 'You are not authorized to edit this event.' );
}
}
$attribute_ids = json_decode ( $this -> request -> data [ 'Attribute' ][ 'attribute_ids' ]);
$attributes = $this -> Attribute -> find ( 'all' , array (
'conditions' => array (
'id' => $attribute_ids ,
'event_id' => $id ,
),
//to_ids = true/false, distribution = [0,1,2,3]
//'fields' => array('id', 'event_id', 'comment', 'to_ids', 'timestamp', 'distribution'),
'recursive' => - 1 ,
));
if ( $this -> request -> data [ 'Attribute' ][ 'to_ids' ] == 2 && $this -> request -> data [ 'Attribute' ][ 'distribution' ] == 4 && $this -> request -> data [ 'Attribute' ][ 'comment' ] == null ) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true )), 'status' => 200 ));
}
if ( $this -> request -> data [ 'Attribute' ][ 'to_ids' ] != 2 ) {
foreach ( $attributes as & $attribute ) $attribute [ 'Attribute' ][ 'to_ids' ] = ( $this -> request -> data [ 'Attribute' ][ 'to_ids' ] == 0 ? false : true );
}
if ( $this -> request -> data [ 'Attribute' ][ 'distribution' ] != 4 ) {
foreach ( $attributes as & $attribute ) $attribute [ 'Attribute' ][ 'distribution' ] = $this -> request -> data [ 'Attribute' ][ 'distribution' ];
}
if ( $this -> request -> data [ 'Attribute' ][ 'comment' ] != null ) {
foreach ( $attributes as & $attribute ) $attribute [ 'Attribute' ][ 'comment' ] = $this -> request -> data [ 'Attribute' ][ 'comment' ];
}
$date = new DateTime ();
$timestamp = $date -> getTimestamp ();
foreach ( $attributes as & $attribute ) $attribute [ 'Attribute' ][ 'timestamp' ] = $timestamp ;
if ( $this -> Attribute -> saveMany ( $attributes )) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true )), 'status' => 200 ));
} else {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false )), 'status' => 200 ));
}
} else {
if ( ! isset ( $id )) throw new MethodNotAllowedException ( 'No event ID provided.' );
$this -> layout = 'ajax' ;
$this -> set ( 'id' , $id );
$this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
$this -> set ( 'distributionDescriptions' , $this -> Attribute -> distributionDescriptions );
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> render ( 'ajax/attributeEditMassForm' );
}
2013-03-04 18:05:17 +01:00
}
/**
* Deletes this specific attribute from all remote servers
* TODO move this to a component ( ? )
*/
private function __deleteAttributeFromServers ( $uuid ) {
2013-07-15 09:10:18 +02:00
// get a list of the servers with push active
2013-03-04 18:05:17 +01:00
$this -> loadModel ( 'Server' );
2013-07-15 09:10:18 +02:00
$servers = $this -> Server -> find ( 'all' , array ( 'conditions' => array ( 'push' => 1 )));
2013-03-04 18:05:17 +01:00
// iterate over the servers and upload the attribute
if ( empty ( $servers ))
return ;
2014-01-16 08:47:25 +01:00
App :: uses ( 'SyncTool' , 'Tools' );
2013-03-04 18:05:17 +01:00
foreach ( $servers as & $server ) {
2014-01-16 08:47:25 +01:00
$syncTool = new SyncTool ();
$HttpSocket = $syncTool -> setupHttpSocket ( $server );
2013-03-04 18:05:17 +01:00
$this -> Attribute -> deleteAttributeFromServer ( $uuid , $server , $HttpSocket );
}
}
public function search () {
$fullAddress = '/attributes/search' ;
if ( $this -> request -> here == $fullAddress ) {
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
// reset the paginate_conditions
$this -> Session -> write ( 'paginate_conditions' , array ());
if ( $this -> request -> is ( 'post' ) && ( $this -> request -> here == $fullAddress )) {
$keyword = $this -> request -> data [ 'Attribute' ][ 'keyword' ];
$keyword2 = $this -> request -> data [ 'Attribute' ][ 'keyword2' ];
2014-11-20 10:40:24 +01:00
$tags = $this -> request -> data [ 'Attribute' ][ 'tags' ];
2013-03-19 11:54:14 +01:00
$org = $this -> request -> data [ 'Attribute' ][ 'org' ];
2013-03-04 18:05:17 +01:00
$type = $this -> request -> data [ 'Attribute' ][ 'type' ];
2013-06-26 15:31:28 +02:00
$ioc = $this -> request -> data [ 'Attribute' ][ 'ioc' ];
$this -> set ( 'ioc' , $ioc );
2013-03-04 18:05:17 +01:00
$category = $this -> request -> data [ 'Attribute' ][ 'category' ];
$this -> set ( 'keywordSearch' , $keyword );
2014-11-20 10:40:24 +01:00
$this -> set ( 'tags' , $tags );
2013-03-04 18:05:17 +01:00
$keyWordText = null ;
$keyWordText2 = null ;
2013-06-24 13:24:08 +02:00
$keyWordText3 = null ;
2013-03-04 18:05:17 +01:00
$this -> set ( 'typeSearch' , $type );
$this -> set ( 'isSearch' , 1 );
$this -> set ( 'categorySearch' , $category );
// search the db
$conditions = array ();
2013-06-26 15:31:28 +02:00
if ( $ioc ) {
$conditions [ 'AND' ][] = array ( 'Attribute.to_ids =' => 1 );
$conditions [ 'AND' ][] = array ( 'Event.published =' => 1 );
}
2013-03-19 11:54:14 +01:00
// search on the value field
2013-03-04 18:05:17 +01:00
if ( isset ( $keyword )) {
2013-04-24 15:20:20 +02:00
$keywordArray = explode ( " \n " , $keyword );
2013-04-25 15:37:49 +02:00
$this -> set ( 'keywordArray' , $keywordArray );
2013-03-04 18:05:17 +01:00
$i = 1 ;
$temp = array ();
2013-06-24 13:24:08 +02:00
$temp2 = array ();
2013-03-04 18:05:17 +01:00
foreach ( $keywordArray as $keywordArrayElement ) {
2014-11-20 10:40:24 +01:00
$saveWord = trim ( strtolower ( $keywordArrayElement ));
if ( $saveWord != '' ) {
$toInclude = true ;
if ( $saveWord [ 0 ] == '!' ) {
$toInclude = false ;
$saveWord = substr ( $saveWord , 1 );
}
if ( preg_match ( '@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$@' , $saveWord )) {
$cidrresults = $this -> Cidr -> CIDR ( $saveWord );
foreach ( $cidrresults as $result ) {
$result = strtolower ( $result );
if ( strpos ( $result , '|' )) {
$resultParts = explode ( '|' , $result );
if ( ! toInclude ) {
$temp2 [] = array (
'AND' => array (
'LOWER(Attribute.value1) NOT LIKE' => $resultParts [ 0 ],
'LOWER(Attribute.value2) NOT LIKE' => $resultParts [ 1 ],
));
} else {
$temp [] = array (
'AND' => array (
'LOWER(Attribute.value1)' => $resultParts [ 0 ],
'LOWER(Attribute.value2)' => $resultParts [ 1 ],
));
}
} else {
if ( ! $toInclude ) {
array_push ( $temp2 , array ( 'LOWER(Attribute.value1) NOT LIKE' => $result ));
array_push ( $temp2 , array ( 'LOWER(Attribute.value2) NOT LIKE' => $result ));
} else {
array_push ( $temp , array ( 'LOWER(Attribute.value1) LIKE' => $result ));
array_push ( $temp , array ( 'LOWER(Attribute.value2) LIKE' => $result ));
}
2013-12-17 11:38:06 +01:00
}
}
2013-06-24 13:24:08 +02:00
} else {
2014-11-20 10:40:24 +01:00
if ( strpos ( $saveWord , '|' )) {
$resultParts = explode ( '|' , $saveWord );
if ( ! $toInclude ) {
$temp2 [] = array (
'AND' => array (
'LOWER(Attribute.value1) NOT LIKE' => '%' . $resultParts [ 0 ],
'LOWER(Attribute.value2) NOT LIKE' => $resultParts [ 1 ] . '%' ,
));
} else {
$temp2 [] = array (
'AND' => array (
'LOWER(Attribute.value1)' => '%' . $resultParts [ 0 ],
'LOWER(Attribute.value2)' => $resultParts [ 1 ] . '%' ,
));
2013-12-17 11:38:06 +01:00
}
} else {
2014-11-20 10:40:24 +01:00
if ( ! $toInclude ) {
array_push ( $temp2 , array ( 'LOWER(Attribute.value1) NOT LIKE' => '%' . $saveWord . '%' ));
array_push ( $temp2 , array ( 'LOWER(Attribute.value2) NOT LIKE' => '%' . $saveWord . '%' ));
} else {
array_push ( $temp , array ( 'LOWER(Attribute.value1) LIKE' => '%' . $saveWord . '%' ));
array_push ( $temp , array ( 'LOWER(Attribute.value2) LIKE' => '%' . $saveWord . '%' ));
}
2013-12-17 11:38:06 +01:00
}
2013-06-24 13:24:08 +02:00
}
2014-12-05 10:13:07 +01:00
if ( $toInclude ) {
array_push ( $temp , array ( 'LOWER(Attribute.comment) LIKE' => '%' . $saveWord . '%' ));
} else {
array_push ( $temp2 , array ( 'LOWER(Attribute.comment) NOT LIKE' => '%' . $saveWord . '%' ));
}
2013-06-24 13:24:08 +02:00
}
2013-03-04 18:05:17 +01:00
if ( $i == 1 && $saveWord != '' ) $keyWordText = $saveWord ;
2013-03-08 13:16:02 +01:00
else if (( $i > 1 && $i < 10 ) && $saveWord != '' ) $keyWordText = $keyWordText . ', ' . $saveWord ;
2013-03-04 18:05:17 +01:00
else if ( $i == 10 && $saveWord != '' ) $keyWordText = $keyWordText . ' and several other keywords' ;
$i ++ ;
}
$this -> set ( 'keywordSearch' , $keyWordText );
2013-03-08 13:16:02 +01:00
if ( ! empty ( $temp )) {
2013-06-24 13:24:08 +02:00
$conditions [ 'AND' ][ 'OR' ] = $temp ;
}
if ( ! empty ( $temp2 )) {
$conditions [ 'AND' ][] = $temp2 ;
2013-03-04 18:05:17 +01:00
}
2013-06-24 13:24:08 +02:00
2013-03-04 18:05:17 +01:00
}
2013-03-19 11:54:14 +01:00
// event IDs to be excluded
2013-03-04 18:05:17 +01:00
if ( isset ( $keyword2 )) {
2013-04-24 15:20:20 +02:00
$keywordArray2 = explode ( " \n " , $keyword2 );
2013-03-04 18:05:17 +01:00
$i = 1 ;
$temp = array ();
foreach ( $keywordArray2 as $keywordArrayElement ) {
$saveWord = trim ( $keywordArrayElement );
2013-06-24 13:24:08 +02:00
if ( empty ( $saveWord )) continue ;
if ( $saveWord [ 0 ] == '!' ) {
2015-08-18 15:37:49 +02:00
if ( strlen ( substr ( $saveWord , 1 )) == 36 ) {
$temp [] = array ( 'Event.uuid !=' => substr ( $saveWord , 1 ));
} else {
$temp [] = array ( 'Attribute.event_id !=' => substr ( $saveWord , 1 ));
}
2013-06-24 13:24:08 +02:00
} else {
2015-08-18 15:37:49 +02:00
if ( strlen ( $saveWord ) == 36 ) {
$temp [ 'OR' ][] = array ( 'Event.uuid =' => $saveWord );
} else {
$temp [ 'OR' ][] = array ( 'Attribute.event_id =' => $saveWord );
}
2013-06-24 13:24:08 +02:00
}
2013-03-04 18:05:17 +01:00
if ( $i == 1 && $saveWord != '' ) $keyWordText2 = $saveWord ;
2013-03-08 13:16:02 +01:00
else if (( $i > 1 && $i < 10 ) && $saveWord != '' ) $keyWordText2 = $keyWordText2 . ', ' . $saveWord ;
2013-03-04 18:05:17 +01:00
else if ( $i == 10 && $saveWord != '' ) $keyWordText2 = $keyWordText2 . ' and several other events' ;
$i ++ ;
}
$this -> set ( 'keywordSearch2' , $keyWordText2 );
2013-03-08 13:16:02 +01:00
if ( ! empty ( $temp )) {
2013-06-24 13:24:08 +02:00
$conditions [ 'AND' ][] = $temp ;
2013-03-04 18:05:17 +01:00
}
}
2014-11-20 10:40:24 +01:00
if ( ! empty ( $tags )) {
$include = array ();
$exclude = array ();
$keywordArray = explode ( " \n " , $tags );
foreach ( $keywordArray as $tagname ) {
$tagname = trim ( $tagname );
if ( substr ( $tagname , 0 , 1 ) === '!' ) $exclude [] = substr ( $tagname , 1 );
else $include [] = $tagname ;
}
$this -> loadModel ( 'Tag' );
if ( ! empty ( $include )) $conditions [ 'AND' ][] = array ( 'OR' => array ( 'Attribute.event_id' => $this -> Tag -> findTags ( $include )));
if ( ! empty ( $exclude )) $conditions [ 'AND' ][] = array ( 'Attribute.event_id !=' => $this -> Tag -> findTags ( $exclude ));
}
2013-03-04 18:05:17 +01:00
if ( $type != 'ALL' ) {
$conditions [ 'Attribute.type =' ] = $type ;
}
if ( $category != 'ALL' ) {
$conditions [ 'Attribute.category =' ] = $category ;
}
2013-03-19 11:54:14 +01:00
// organisation search field
2013-06-28 14:28:58 +02:00
$i = 1 ;
2013-06-24 13:24:08 +02:00
$temp = array ();
if ( isset ( $org )) {
$orgArray = explode ( " \n " , $org );
foreach ( $orgArray as $orgArrayElement ) {
$saveWord = trim ( $orgArrayElement );
if ( empty ( $saveWord )) continue ;
if ( $saveWord [ 0 ] == '!' ) {
$temp [] = array ( 'Event.orgc NOT LIKE ' => '%' . substr ( $saveWord , 1 ) . '%' );
} else {
$temp [ 'OR' ][] = array ( 'Event.orgc LIKE ' => '%' . $saveWord . '%' );
}
}
if ( $i == 1 && $saveWord != '' ) $keyWordText3 = $saveWord ;
else if (( $i > 1 && $i < 10 ) && $saveWord != '' ) $keyWordText3 = $keyWordText3 . ', ' . $saveWord ;
else if ( $i == 10 && $saveWord != '' ) $keyWordText3 = $keyWordText3 . ' and several other organisations' ;
$i ++ ;
$this -> set ( 'orgSearch' , $keyWordText3 );
if ( ! empty ( $temp )) {
$conditions [ 'AND' ][] = $temp ;
}
2013-03-19 11:54:14 +01:00
}
2014-03-13 16:03:16 +01:00
if ( $this -> request -> data [ 'Attribute' ][ 'alternate' ]) {
$events = $this -> searchAlternate ( $conditions );
$this -> set ( 'events' , $events );
$this -> render ( 'alternate_search_result' );
} else {
$this -> Attribute -> recursive = 0 ;
$this -> paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 , // LATER we will bump here on a problem once we have more than 9999 attributes?
'conditions' => $conditions ,
2014-12-03 17:23:32 +01:00
'contain' => array ( 'Event.orgc' , 'Event.id' , 'Event.org' , 'Event.user_id' , 'Event.info' )
2013-04-17 11:13:09 +02:00
);
2014-03-13 16:03:16 +01:00
if ( ! $this -> _isSiteAdmin ()) {
// merge in private conditions
$this -> paginate = Set :: merge ( $this -> paginate , array (
'conditions' =>
2015-02-05 17:40:56 +01:00
array ( " OR " =>
array (
array ( 'Event.org =' => $this -> Auth -> user ( 'org' )),
array ( " AND " =>
array ( 'Event.org !=' => $this -> Auth -> user ( 'org' )),
array ( 'Event.distribution !=' => 0 ),
array ( 'Attribute.distribution !=' => 0 ),
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published =' => 1 ) : array (),
)
2015-02-05 17:16:40 +01:00
)
)
2014-03-13 16:03:16 +01:00
)
);
}
$idList = array ();
$attributeIdList = array ();
$attributes = $this -> paginate ();
// if we searched for IOCs only, apply the whitelist to the search result!
if ( $ioc ) {
$this -> loadModel ( 'Whitelist' );
$attributes = $this -> Whitelist -> removeWhitelistedFromArray ( $attributes , true );
2013-03-18 11:48:36 +01:00
}
2014-03-13 16:03:16 +01:00
foreach ( $attributes as & $attribute ) {
$attributeIdList [] = $attribute [ 'Attribute' ][ 'id' ];
if ( ! in_array ( $attribute [ 'Attribute' ][ 'event_id' ], $idList )) {
$idList [] = $attribute [ 'Attribute' ][ 'event_id' ];
}
}
$this -> set ( 'attributes' , $attributes );
// and store into session
$this -> Session -> write ( 'paginate_conditions' , $this -> paginate );
$this -> Session -> write ( 'paginate_conditions_keyword' , $keyword );
$this -> Session -> write ( 'paginate_conditions_keyword2' , $keyword2 );
$this -> Session -> write ( 'paginate_conditions_org' , $org );
$this -> Session -> write ( 'paginate_conditions_type' , $type );
2014-04-15 17:11:12 +02:00
$this -> Session -> write ( 'paginate_conditions_ioc' , $ioc );
2014-11-20 10:40:24 +01:00
$this -> Session -> write ( 'paginate_conditions_tags' , $tags );
2014-03-13 16:03:16 +01:00
$this -> Session -> write ( 'paginate_conditions_category' , $category );
$this -> Session -> write ( 'search_find_idlist' , $idList );
$this -> Session -> write ( 'search_find_attributeidlist' , $attributeIdList );
// set the same view as the index page
$this -> render ( 'index' );
2013-03-04 18:05:17 +01:00
}
} else {
// no search keyword is given, show the search form
// adding filtering by category and type
// combobox for types
$types = array ( '' => array ( 'ALL' => 'ALL' ), 'types' => array ());
$types [ 'types' ] = array_merge ( $types [ 'types' ], $this -> _arrayToValuesIndexArray ( array_keys ( $this -> Attribute -> typeDefinitions )));
$this -> set ( 'types' , $types );
// combobox for categories
$categories = array ( '' => array ( 'ALL' => 'ALL' , '' => '' ), 'categories' => array ());
array_pop ( $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ]); // remove that last 'empty' item
$categories [ 'categories' ] = array_merge ( $categories [ 'categories' ], $this -> _arrayToValuesIndexArray ( $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ]));
$this -> set ( 'categories' , $categories );
}
} else {
$this -> set ( 'attrDescriptions' , $this -> Attribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> Attribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
// get from Session
$keyword = $this -> Session -> read ( 'paginate_conditions_keyword' );
2013-06-28 14:28:58 +02:00
$keyword2 = $this -> Session -> read ( 'paginate_conditions_keyword2' );
$org = $this -> Session -> read ( 'paginate_conditions_org' );
2013-03-04 18:05:17 +01:00
$type = $this -> Session -> read ( 'paginate_conditions_type' );
$category = $this -> Session -> read ( 'paginate_conditions_category' );
2014-11-20 10:40:24 +01:00
$tags = $this -> Session -> read ( 'paginate_conditions_tags' );
2013-03-04 18:05:17 +01:00
$this -> set ( 'keywordSearch' , $keyword );
2013-06-28 14:28:58 +02:00
$this -> set ( 'keywordSearch2' , $keyword2 );
$this -> set ( 'orgSearch' , $org );
2013-03-04 18:05:17 +01:00
$this -> set ( 'typeSearch' , $type );
2014-11-20 10:40:24 +01:00
$this -> set ( 'tags' , $tags );
2013-03-04 18:05:17 +01:00
$this -> set ( 'isSearch' , 1 );
$this -> set ( 'categorySearch' , $category );
// re-get pagination
$this -> Attribute -> recursive = 0 ;
$this -> paginate = $this -> Session -> read ( 'paginate_conditions' );
2013-04-24 15:20:20 +02:00
$this -> set ( 'attributes' , $this -> paginate ());
2013-03-04 18:05:17 +01:00
// set the same view as the index page
$this -> render ( 'index' );
}
}
2014-03-13 16:03:16 +01: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 ) {
$data [ 'AND' ][] = array (
" OR " => array (
2015-02-05 17:16:40 +01:00
array ( 'Event.org =' => $this -> Auth -> user ( 'org' )),
array ( " AND " => array ( 'Event.org !=' => $this -> Auth -> user ( 'org' )),
array ( 'Event.distribution !=' => 0 ),
array ( 'Attribute.distribution !=' => 0 ),
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published =' => 1 ) : array (),
)
)
);
2014-03-13 16:03:16 +01:00
$attributes = $this -> Attribute -> find ( 'all' , array (
'conditions' => $data ,
'fields' => array (
'Attribute.id' , 'Attribute.event_id' , 'Attribute.type' , 'Attribute.category' , 'Attribute.to_ids' , 'Attribute.value' , 'Attribute.distribution' ,
'Event.id' , 'Event.org' , 'Event.orgc' , 'Event.info' , 'Event.distribution' , 'Event.attribute_count'
)));
$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 & $event ) {
$event [ 'relevance' ] = 100 * $event [ 'to_ids' ] / ( $event [ 'no_ids' ] + $event [ 'to_ids' ]);
}
2014-04-15 17:11:12 +02:00
if ( ! empty ( $events )) $events = $this -> __subval_sort ( $events , 'relevance' );
2014-03-13 16:03:16 +01:00
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 ;
}
2013-03-04 18:05:17 +01:00
2013-03-18 11:48:36 +01:00
public function downloadAttributes () {
$idList = $this -> Session -> read ( 'search_find_idlist' );
$this -> response -> type ( 'xml' ); // set the content type
$this -> header ( 'Content-Disposition: download; filename="misp.attribute.search.xml"' );
$this -> layout = 'xml/default' ;
$this -> loadModel ( 'Attribute' );
if ( ! isset ( $idList )) {
print " No results found to export \n " ;
} else {
foreach ( $idList as $listElement ) {
$put [ 'OR' ][] = array ( 'Attribute.id' => $listElement );
}
$conditions [ 'AND' ][] = $put ;
// restricting to non-private or same org if the user is not a site-admin.
if ( ! $this -> _isSiteAdmin ()) {
$temp = array ();
2013-06-10 17:33:03 +02:00
array_push ( $temp , array ( 'Attribute.distribution >' => 0 ));
2013-03-18 11:48:36 +01:00
array_push ( $temp , array ( 'OR' => $distribution ));
array_push ( $temp , array ( '(SELECT events.org FROM events WHERE events.id = Attribute.event_id) LIKE' => $this -> _checkOrg ()));
$put2 [ 'OR' ][] = $temp ;
$conditions [ 'AND' ][] = $put2 ;
}
$params = array (
'conditions' => $conditions , //array of conditions
'recursive' => 0 , //int
'fields' => array ( 'Attribute.id' , 'Attribute.value' ), //array of field names
'order' => array ( 'Attribute.id' ), //string or array defining order
);
$attributes = $this -> Attribute -> find ( 'all' , $params );
$this -> set ( 'results' , $attributes );
}
$this -> render ( 'xml' );
}
2013-03-04 18:05:17 +01:00
public function checkComposites () {
if ( ! self :: _isAdmin ()) throw new NotFoundException ();
$this -> set ( 'fails' , $this -> Attribute -> checkComposites ());
}
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
// Use the rest interface to search for attributes. Usage:
// MISP-base-url/attributes/restSearch/[api-key]/[value]/[type]/[category]/[orgc]
// value, type, category, orgc are optional
// the last 4 fields accept the following operators:
// && - you can use && between two search values to put a logical OR between them. for value, 1.1.1.1&&2.2.2.2 would find attributes with the value being either of the two.
// ! - you can negate a search term. For example: google.com&&!mail would search for all attributes with value google.com but not ones that include mail. www.google.com would get returned, mail.google.com wouldn't.
2015-08-18 19:51:41 +02:00
public function restSearch ( $key = 'download' , $value = false , $type = false , $category = false , $org = false , $tags = false , $from = false , $to = false , $last = false , $eventid = false ) {
2014-02-19 17:07:24 +01:00
if ( $tags ) $tags = str_replace ( ';' , ':' , $tags );
2014-01-16 17:19:51 +01:00
if ( $key != null && $key != 'download' ) {
$user = $this -> checkAuthUser ( $key );
} 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.' );
$user = $this -> checkAuthUser ( $this -> Auth -> user ( 'authkey' ));
}
2013-09-19 12:05:08 +02:00
if ( ! $user ) {
throw new UnauthorizedException ( 'This authentication key is not authorized to be used for exports. Contact your administrator.' );
}
2013-12-17 11:38:06 +01:00
$value = str_replace ( '|' , '/' , $value );
2014-03-21 15:30:49 +01:00
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
// For Json: {"request":{"value": "7.7.7.7&&1.1.1.1","type":"ip-src"}}
// For XML: <request><value>7.7.7.7&&1.1.1.1</value><type>ip-src</type></request>
// the response type is used to determine the parsing method (xml/json)
if ( $this -> request -> is ( 'post' )) {
if ( $this -> response -> type () === 'application/json' ) {
$data = $this -> request -> input ( 'json_decode' , true );
} elseif ( $this -> response -> type () === 'application/xml' && ! empty ( $this -> request -> data )) {
$data = $this -> request -> data ;
} else {
throw new BadRequestException ( 'Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct accept and content type headers.' );
}
2015-08-18 19:51:41 +02:00
$paramArray = array ( 'value' , 'type' , 'category' , 'org' , 'tags' , 'from' , 'to' , 'last' , 'eventid' );
2014-03-21 15:30:49 +01:00
foreach ( $paramArray as $p ) {
if ( isset ( $data [ 'request' ][ $p ])) ${$p} = $data [ 'request' ][ $p ];
else ${$p} = null ;
}
}
2015-08-18 19:51:41 +02:00
$simpleFalse = array ( 'value' , 'type' , 'category' , 'org' , 'tags' , 'from' , 'to' , 'last' , 'eventid' );
2015-05-13 16:12:06 +02:00
foreach ( $simpleFalse as $sF ) {
2015-08-18 19:51:41 +02:00
if ( ! is_array ( ${$sF} ) && ( ${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower ( ${$sF} )) === 'false' ) ${$sF} = false ;
2015-05-13 16:12:06 +02:00
}
if ( $from ) $from = $this -> Attribute -> Event -> dateFieldCheck ( $from );
2015-05-16 01:31:18 +02:00
if ( $to ) $to = $this -> Attribute -> Event -> dateFieldCheck ( $to );
Added a new API parameter that allows to restrict events to the most recently published ones, #527
- added the new flag "last" to the list of parameters
- exports affected: XML, CSV, NIDS, HIDS, STIX, Text, RestSearch
- Valid values: number + format where format can be d, m, h for day, minute, hour (examples: 5d or 12h or 30m)
2015-06-06 20:00:57 +02:00
if ( $last ) $last = $this -> Attribute -> Event -> resolveTimeDelta ( $last );
2014-03-20 15:15:51 +01:00
if ( ! isset ( $this -> request -> params [ 'ext' ]) || $this -> request -> params [ 'ext' ] !== 'json' ) {
$this -> response -> type ( 'xml' ); // set the content type
$this -> layout = 'xml/default' ;
$this -> header ( 'Content-Disposition: download; filename="misp.search.attribute.results.xml"' );
} else {
$this -> response -> type ( 'json' ); // set the content type
$this -> layout = 'json/default' ;
$this -> header ( 'Content-Disposition: download; filename="misp.search.attribute.results.json"' );
}
2013-09-19 12:05:08 +02:00
$conditions [ 'AND' ] = array ();
$subcondition = array ();
$this -> loadModel ( 'Attribute' );
// add the values as specified in the 2nd parameter to the conditions
$values = explode ( '&&' , $value );
2015-08-18 19:51:41 +02:00
$parameters = array ( 'value' , 'type' , 'category' , 'org' , 'eventid' );
2013-09-19 12:05:08 +02:00
foreach ( $parameters as $k => $param ) {
2014-02-02 18:10:21 +01:00
if ( isset ( $ { $parameters [ $k ]}) && $ { $parameters [ $k ]} !== 'null' ) {
2015-08-18 19:51:41 +02:00
if ( is_array ( $ { $parameters [ $k ]})) $elements = $ { $parameters [ $k ]};
else $elements = explode ( '&&' , $ { $parameters [ $k ]});
2013-09-19 12:05:08 +02:00
foreach ( $elements as $v ) {
if ( substr ( $v , 0 , 1 ) == '!' ) {
2013-12-17 11:38:06 +01:00
if ( $parameters [ $k ] === 'value' && preg_match ( '@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$@' , substr ( $v , 1 ))) {
$cidrresults = $this -> Cidr -> CIDR ( substr ( $v , 1 ));
foreach ( $cidrresults as $result ) {
$subcondition [ 'AND' ][] = array ( 'Attribute.value NOT LIKE' => $result );
}
} else {
if ( $parameters [ $k ] === 'org' ) {
$subcondition [ 'AND' ][] = array ( 'Event.' . $parameters [ $k ] . ' NOT LIKE' => '%' . substr ( $v , 1 ) . '%' );
2015-08-18 19:51:41 +02:00
} elseif ( $parameters [ $k ] === 'eventid' ) {
$subcondition [ 'AND' ][] = array ( 'Attribute.event_id !=' => substr ( $v , 1 ));
2013-12-17 11:38:06 +01:00
} else {
$subcondition [ 'AND' ][] = array ( 'Attribute.' . $parameters [ $k ] . ' NOT LIKE' => '%' . substr ( $v , 1 ) . '%' );
}
}
2013-09-19 12:05:08 +02:00
} else {
2013-12-17 11:38:06 +01:00
if ( $parameters [ $k ] === 'value' && preg_match ( '@^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$@' , substr ( $v , 1 ))) {
$cidrresults = $this -> Cidr -> CIDR ( $v );
foreach ( $cidrresults as $result ) {
$subcondition [ 'OR' ][] = array ( 'Attribute.value LIKE' => $result );
}
} else {
if ( $parameters [ $k ] === 'org' ) {
$subcondition [ 'OR' ][] = array ( 'Event.' . $parameters [ $k ] . ' LIKE' => '%' . $v . '%' );
2015-08-18 19:51:41 +02:00
} elseif ( $parameters [ $k ] === 'eventid' ) {
$subcondition [ 'OR' ][] = array ( 'Attribute.event_id' => $v );
2013-12-17 11:38:06 +01:00
} else {
$subcondition [ 'OR' ][] = array ( 'Attribute.' . $parameters [ $k ] . ' LIKE' => '%' . $v . '%' );
}
}
2013-09-19 12:05:08 +02:00
}
}
array_push ( $conditions [ 'AND' ], $subcondition );
$subcondition = array ();
}
}
// If we are looking for an attribute, we want to retrieve some extra data about the event to be able to check for the permissions.
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
if ( ! $user [ 'User' ][ 'siteAdmin' ]) {
$temp = array ();
2015-02-05 17:16:40 +01:00
$temp [ 'AND' ] = array (
'Event.distribution >' => 0 ,
'Attribute.distribution >' => 0 ,
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published =' => 1 ) : array ()
);
2013-09-19 12:05:08 +02:00
$subcondition [ 'OR' ][] = $temp ;
$subcondition [ 'OR' ][] = array ( 'Event.org' => $user [ 'User' ][ 'org' ]);
array_push ( $conditions [ 'AND' ], $subcondition );
}
2014-02-02 18:10:21 +01:00
// If we sent any tags along, load the associated tag names for each attribute
2014-03-24 16:33:40 +01:00
if ( $tags ) {
2014-02-02 18:10:21 +01:00
$args = $this -> Attribute -> dissectArgs ( $tags );
$this -> loadModel ( 'Tag' );
$tagArray = $this -> Tag -> fetchEventTagIds ( $args [ 0 ], $args [ 1 ]);
$temp = array ();
foreach ( $tagArray [ 0 ] as $accepted ) {
$temp [ 'OR' ][] = array ( 'Event.id' => $accepted );
}
$conditions [ 'AND' ][] = $temp ;
$temp = array ();
foreach ( $tagArray [ 1 ] as $rejected ) {
$temp [ 'AND' ][] = array ( 'Event.id !=' => $rejected );
}
$conditions [ 'AND' ][] = $temp ;
}
2015-02-03 17:06:05 +01:00
if ( $from ) $conditions [ 'AND' ][] = array ( 'Event.date >=' => $from );
if ( $to ) $conditions [ 'AND' ][] = array ( 'Event.date <=' => $to );
Added a new API parameter that allows to restrict events to the most recently published ones, #527
- added the new flag "last" to the list of parameters
- exports affected: XML, CSV, NIDS, HIDS, STIX, Text, RestSearch
- Valid values: number + format where format can be d, m, h for day, minute, hour (examples: 5d or 12h or 30m)
2015-06-06 20:00:57 +02:00
if ( $last ) $conditions [ 'AND' ][] = array ( 'Event.publish_timestamp >=' => $last );
2015-02-03 17:06:05 +01:00
2013-09-20 11:40:26 +02:00
// change the fields here for the attribute export!!!! Don't forget to check for the permissions, since you are not going through fetchevent. Maybe create fetchattribute?
2014-02-02 18:10:21 +01:00
2013-09-20 11:40:26 +02:00
$params = array (
'conditions' => $conditions ,
'fields' => array ( 'Attribute.*' , 'Event.org' , 'Event.distribution' ),
2014-02-02 18:10:21 +01:00
'contain' => array ( 'Event' => array ())
2013-09-20 11:40:26 +02:00
);
2013-09-19 12:05:08 +02:00
$results = $this -> Attribute -> find ( 'all' , $params );
$this -> loadModel ( 'Whitelist' );
2014-03-20 15:15:51 +01:00
$results = $this -> Whitelist -> removeWhitelistedFromArray ( $results , true );
2013-09-20 11:40:26 +02:00
if ( empty ( $results )) throw new NotFoundException ( 'No matches.' );
2013-09-19 12:05:08 +02:00
$this -> set ( 'results' , $results );
}
2013-11-12 16:23:37 +01: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.
2013-09-19 12:05:08 +02:00
// 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>/<type>/<signature flag>
// The signature flag is off by default, enabling it will only return attribugtes that have the to_ids flag set to true.
2014-03-21 15:30:49 +01:00
public function returnAttributes ( $key = 'download' , $id , $type = null , $sigOnly = false ) {
2013-09-19 12:05:08 +02:00
$user = $this -> checkAuthUser ( $key );
2013-09-19 17:28:55 +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.
2014-03-21 15:30:49 +01:00
if ( $key != null && $key != 'download' ) {
$user = $this -> checkAuthUser ( $key );
} 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.' );
$user = $this -> checkAuthUser ( $this -> Auth -> user ( 'authkey' ));
}
2013-09-19 12:05:08 +02:00
if ( ! $user ) {
throw new UnauthorizedException ( 'This authentication key is not authorized to be used for exports. Contact your administrator.' );
}
2014-03-21 15:30:49 +01:00
if ( $this -> request -> is ( 'post' )) {
if ( $this -> response -> type () === 'application/json' ) {
$data = $this -> request -> input ( 'json_decode' , true );
} elseif ( $this -> response -> type () === 'application/xml' && ! empty ( $this -> request -> data )) {
$data = $this -> request -> data ;
} else {
throw new BadRequestException ( 'Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct accept and content type headers.' );
}
$paramArray = array ( 'type' , 'sigOnly' );
foreach ( $paramArray as $p ) {
if ( isset ( $data [ 'request' ][ $p ])) ${$p} = $data [ 'request' ][ $p ];
else ${$p} = null ;
}
}
2013-09-19 12:05:08 +02:00
$this -> loadModel ( 'Event' );
$this -> Event -> read ( null , $id );
$myEventOrAdmin = false ;
if ( $user [ 'User' ][ 'siteAdmin' ] || $this -> Event -> data [ 'Event' ][ 'org' ] == $user [ 'User' ][ 'org' ]) {
$myEventOrAdmin = true ;
}
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
if ( ! $myEventOrAdmin ) {
if ( $this -> Event -> data [ 'Event' ][ 'distribution' ] == 0 ) {
throw new UnauthorizedException ( 'You don\'t have access to that event.' );
2013-11-12 16:23:37 +01:00
}
2013-09-19 12:05:08 +02:00
}
$this -> response -> type ( 'xml' ); // set the content type
$this -> layout = 'xml/default' ;
$this -> header ( 'Content-Disposition: download; filename="misp.search.attribute.results.xml"' );
// check if user can see the event!
$conditions [ 'AND' ] = array ();
$include = array ();
$exclude = array ();
$attributes = array ();
// If there is a type set, create the include and exclude arrays from it
if ( isset ( $type )) {
$elements = explode ( '&&' , $type );
foreach ( $elements as $v ) {
if ( substr ( $v , 0 , 1 ) == '!' ) {
$exclude [] = substr ( $v , 1 );
} else {
$include [] = $v ;
}
}
}
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
// check each attribute
foreach ( $this -> Event -> data [ 'Attribute' ] as $k => $attribute ) {
$contained = false ;
// If the include list is empty, then we just then the first check should always set contained to true (basically we chose type = all - exclusions, or simply all)
if ( empty ( $include )) {
$contained = true ;
} else {
// If we have elements in $include we should check if the attribute's type should be included
foreach ( $include as $inc ) {
if ( strpos ( $attribute [ 'type' ], $inc ) !== false ) {
$contained = true ;
}
}
}
// If we have either everything included or the attribute passed the include check, we should check if there is a reason to exclude the attribute
// For example, filename may be included, but md5 may be excluded, meaning that filename|md5 should be removed
if ( $contained ) {
foreach ( $exclude as $exc ) {
if ( strpos ( $attribute [ 'type' ], $exc ) !== false ) {
$contained = false ;
2013-11-12 16:23:37 +01:00
continue 2 ;
}
2013-09-19 12:05:08 +02:00
}
}
// If we still didn't throw the attribute away, let's check if the user requesting the attributes is of the owning organisation of the event
// and if not, whether the distribution of the attribute allows the user to see it
if ( $contained && ! $myEventOrAdmin && $attribute [ 'distribution' ] == 0 ) {
$contained = false ;
}
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
// If we have set the sigOnly parameter and the attribute has to_ids set to false, discard it!
2013-09-20 11:40:26 +02:00
if ( $contained && $sigOnly === 'true' && ! $attribute [ 'to_ids' ]) {
2013-09-19 12:05:08 +02:00
$contained = false ;
}
2013-11-12 16:23:37 +01:00
2013-09-19 12:05:08 +02:00
// If after all of this $contained is still true, let's add the attribute to the array
if ( $contained ) $attributes [] = $attribute ;
}
2013-09-20 11:40:26 +02:00
if ( empty ( $attributes )) throw new NotFoundException ( 'No matches.' );
2013-09-19 12:05:08 +02:00
$this -> set ( 'results' , $attributes );
}
2013-11-12 16:23:37 +01:00
2014-01-16 17:19:51 +01:00
public function downloadAttachment ( $key = 'download' , $id ) {
if ( $key != null && $key != 'download' ) {
$user = $this -> checkAuthUser ( $key );
} 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.' );
$user = $this -> checkAuthUser ( $this -> Auth -> user ( 'authkey' ));
}
2013-09-19 17:28:55 +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.' );
}
2013-09-20 11:40:26 +02:00
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( 'Invalid attribute or no authorisation to view it.' );
}
2013-09-19 17:28:55 +02:00
$this -> Attribute -> read ( null , $id );
2013-11-12 16:23:37 +01:00
if ( ! $user [ 'User' ][ 'siteAdmin' ] &&
$user [ 'User' ][ 'org' ] != $this -> Attribute -> data [ 'Event' ][ 'org' ] &&
( $this -> Attribute -> data [ 'Event' ][ 'distribution' ] == 0 ||
2013-09-19 17:28:55 +02:00
$this -> Attribute -> data [ 'Attribute' ][ 'distribution' ] == 0
)) {
2013-09-20 11:40:26 +02:00
throw new NotFoundException ( 'Invalid attribute or no authorisation to view it.' );
2013-09-19 17:28:55 +02:00
}
$this -> __downloadAttachment ( $this -> Attribute -> data [ 'Attribute' ]);
}
2013-11-15 15:39:34 +01:00
Added a new API parameter that allows to restrict events to the most recently published ones, #527
- added the new flag "last" to the list of parameters
- exports affected: XML, CSV, NIDS, HIDS, STIX, Text, RestSearch
- Valid values: number + format where format can be d, m, h for day, minute, hour (examples: 5d or 12h or 30m)
2015-06-06 20:00:57 +02:00
public function text ( $key = 'download' , $type = 'all' , $tags = false , $eventId = false , $allowNonIDS = false , $from = false , $to = false , $last = false ) {
$simpleFalse = array ( 'eventId' , 'allowNonIDS' , 'tags' , 'from' , 'to' , 'last' );
2015-02-03 17:06:05 +01:00
foreach ( $simpleFalse as $sF ) {
if ( ${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || strtolower ( ${$sF} ) === 'false' ) ${$sF} = false ;
}
2014-12-19 13:32:16 +01:00
if ( $type === 'null' || $type === '0' || $type === 'false' ) $type = 'all' ;
2015-05-13 16:12:06 +02:00
if ( $from ) $from = $this -> Attribute -> Event -> dateFieldCheck ( $from );
2015-05-16 01:31:18 +02:00
if ( $to ) $to = $this -> Attribute -> Event -> dateFieldCheck ( $to );
Added a new API parameter that allows to restrict events to the most recently published ones, #527
- added the new flag "last" to the list of parameters
- exports affected: XML, CSV, NIDS, HIDS, STIX, Text, RestSearch
- Valid values: number + format where format can be d, m, h for day, minute, hour (examples: 5d or 12h or 30m)
2015-06-06 20:00:57 +02:00
if ( $last ) $last = $this -> Attribute -> Event -> resolveTimeDelta ( $last );
2013-11-15 15:39:34 +01:00
if ( $key != 'download' ) {
// check if the key is valid -> search for users based on key
$user = $this -> checkAuthUser ( $key );
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.' );
}
}
2014-01-10 13:56:35 +01:00
$this -> response -> type ( 'txt' ); // set the content type
$this -> header ( 'Content-Disposition: download; filename="misp.' . $type . '.txt"' );
$this -> layout = 'text/default' ;
Added a new API parameter that allows to restrict events to the most recently published ones, #527
- added the new flag "last" to the list of parameters
- exports affected: XML, CSV, NIDS, HIDS, STIX, Text, RestSearch
- Valid values: number + format where format can be d, m, h for day, minute, hour (examples: 5d or 12h or 30m)
2015-06-06 20:00:57 +02:00
$attributes = $this -> Attribute -> text ( $this -> _checkOrg (), $this -> _isSiteAdmin (), $type , $tags , $eventId , $allowNonIDS , $from , $to , $last );
2013-11-15 15:39:34 +01:00
$this -> loadModel ( 'Whitelist' );
$attributes = $this -> Whitelist -> removeWhitelistedFromArray ( $attributes , true );
$this -> set ( 'attributes' , $attributes );
}
2014-01-16 17:19:51 +01:00
2015-05-20 15:04:41 +02:00
public function rpz ( $key = 'download' , $tags = false , $eventId = false , $from = false , $to = false , $policy = false , $walled_garden = false , $ns = false , $email = false , $serial = false , $refresh = false , $retry = false , $expiry = false , $minimum_ttl = false , $ttl = false ) {
2015-05-19 15:25:45 +02:00
// request handler for POSTed queries. If the request is a post, the parameters (apart from the key) will be ignored and replaced by the terms defined in the posted json or xml object.
// The correct format for both is a "request" root element, as shown by the examples below:
2015-05-20 15:04:41 +02:00
// For Json: {"request":{"policy": "walled-garden","garden":"garden.example.com"}}
// For XML: <request><policy>walled-garden</policy><garden>garden.example.com</gargen></request>
2015-05-19 15:25:45 +02:00
// the response type is used to determine the parsing method (xml/json)
if ( $this -> request -> is ( 'post' )) {
2015-05-20 15:04:41 +02:00
if ( $this -> request -> input ( 'json_decode' , true )) {
2015-05-19 15:25:45 +02:00
$data = $this -> request -> input ( 'json_decode' , true );
} else {
2015-05-20 15:04:41 +02:00
$data = $this -> request -> data ;
2015-05-19 15:25:45 +02:00
}
2015-05-20 15:04:41 +02:00
if ( empty ( $data )) throw new BadRequestException ( 'Either specify the search terms in the url, or POST a json array / xml (with the root element being "request" and specify the correct headers based on content type.' );
$paramArray = array ( 'eventId' , 'tags' , 'from' , 'to' , 'policy' , 'walled_garden' , 'ns' , 'email' , 'serial' , 'refresh' , 'retry' , 'expiry' , 'minimum_ttl' , 'ttl' );
2015-05-19 15:25:45 +02:00
foreach ( $paramArray as $p ) {
if ( isset ( $data [ 'request' ][ $p ])) ${$p} = $data [ 'request' ][ $p ];
else ${$p} = null ;
}
}
2015-05-20 15:04:41 +02:00
$simpleFalse = array ( 'eventId' , 'tags' , 'from' , 'to' , 'policy' , 'walled_garden' , 'ns' , 'email' , 'serial' , 'refresh' , 'retry' , 'expiry' , 'minimum_ttl' , 'ttl' );
2015-05-15 14:58:53 +02:00
foreach ( $simpleFalse as $sF ) {
2015-05-20 15:04:41 +02:00
if ( ${$sF} === 'null' || ${$sF} == '0' || ${$sF} === false || ${$sF} === null || strtolower ( ${$sF} ) === 'false' ) ${$sF} = false ;
2015-05-15 14:58:53 +02:00
}
2015-05-20 15:04:41 +02:00
if ( ! in_array ( $policy , array ( 'NXDOMAIN' , 'NODATA' , 'DROP' , 'walled-garden' ))) $policy = false ;
App :: uses ( 'RPZExport' , 'Export' );
$rpzExport = new RPZExport ();
if ( $policy ) $policy = $rpzExport -> getIdByPolicy ( $policy );
2015-05-20 16:23:42 +02:00
2015-05-19 15:25:45 +02:00
$this -> loadModel ( 'Server' );
$rpzSettings = array ();
2015-05-20 16:23:42 +02:00
$lookupData = array ( 'policy' , 'walled_garden' , 'ns' , 'email' , 'serial' , 'refresh' , 'retry' , 'expiry' , 'minimum_ttl' , 'ttl' );
2015-05-20 15:04:41 +02:00
foreach ( $lookupData as $v ) {
if ( ${$v} !== false ) $rpzSettings [ $v ] = ${$v} ;
2015-05-19 15:25:45 +02:00
else {
2015-05-20 15:04:41 +02:00
$tempSetting = Configure :: read ( 'Plugin.RPZ_' . $v );
if ( isset ( $tempSetting )) $rpzSettings [ $v ] = Configure :: read ( 'Plugin.RPZ_' . $v );
else $rpzSettings [ $v ] = $this -> Server -> serverSettings [ 'Plugin' ][ 'RPZ_' . $v ][ 'value' ];
2015-05-19 15:25:45 +02:00
}
}
2015-05-15 14:58:53 +02:00
if ( $from ) $from = $this -> Attribute -> Event -> dateFieldCheck ( $from );
if ( $to ) $from = $this -> Attribute -> Event -> dateFieldCheck ( $to );
if ( $key != 'download' ) {
// check if the key is valid -> search for users based on key
$user = $this -> checkAuthUser ( $key );
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.' );
}
}
$values = $this -> Attribute -> rpz ( $this -> _checkOrg (), $this -> _isSiteAdmin (), $tags , $eventId , $from , $to );
$this -> response -> type ( 'txt' ); // set the content type
$file = '' ;
if ( $tags ) $file = 'filtered.' ;
if ( $eventId ) $file .= 'event-' . $eventId . '.' ;
if ( $from ) $file .= 'from-' . $from . '.' ;
if ( $to ) $file .= 'to-' . $to . '.' ;
2015-05-20 16:28:59 +02:00
if ( $file == '' ) $file = 'all.' ;
$this -> header ( 'Content-Disposition: download; filename="misp.rpz.' . $file . 'txt"' );
2015-05-15 14:58:53 +02:00
$this -> layout = 'text/default' ;
$this -> loadModel ( 'Whitelist' );
$values = $this -> Whitelist -> removeWhitelistedValuesFromArray ( $values );
$this -> set ( 'values' , $values );
2015-05-19 15:25:45 +02:00
$this -> set ( 'rpzSettings' , $rpzSettings );
2015-05-15 14:58:53 +02:00
}
2014-01-16 17:19:51 +01:00
2015-09-03 10:58:54 +02:00
public function reportValidationIssuesAttributes ( $eventId = false ) {
2014-01-16 17:19:51 +01:00
// 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 ();
2015-09-03 10:58:54 +02:00
$this -> set ( 'result' , $this -> Attribute -> reportValidationIssuesAttributes ( $eventId ));
2014-01-16 17:19:51 +01:00
}
2014-01-17 09:53:23 +01:00
2014-01-16 17:19:51 +01:00
public function generateCorrelation () {
2014-01-17 09:53:23 +01:00
if ( ! self :: _isSiteAdmin ()) throw new NotFoundException ();
2014-11-20 10:40:24 +01:00
if ( ! Configure :: read ( 'MISP.background_jobs' )) {
$k = $this -> Attribute -> generateCorrelation ();
$this -> Session -> setFlash ( __ ( '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 )
);
$job -> saveField ( 'process_id' , $process_id );
$this -> Session -> setFlash ( __ ( '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' ));
}
2014-01-16 17:19:51 +01:00
}
2014-04-17 11:44:40 +02:00
public function fetchViewValue ( $id , $field = null ) {
$validFields = array ( 'value' , 'comment' , 'type' , 'category' , 'to_ids' , 'distribution' , 'timestamp' );
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.');
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$attribute = $this -> Attribute -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Attribute.id' => $id ),
'fields' => array ( 'id' , 'distribution' , 'event_id' , $field ),
'contain' => array (
'Event' => array (
'fields' => array ( 'distribution' , 'id' , 'org' ),
)
)
));
if ( ! $this -> _isSiteAdmin ()) {
//
2014-05-07 17:16:19 +02:00
if ( ! ( $attribute [ 'Event' ][ 'org' ] == $this -> Auth -> user ( 'org' ) || ( $attribute [ 'Event' ][ 'distribution' ] > 0 && $attribute [ 'Attribute' ][ 'distribution' ] > 0 ))) {
2014-04-17 11:44:40 +02:00
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
}
$result = $attribute [ 'Attribute' ][ $field ];
if ( $field == 'distribution' ) $result = $this -> Attribute -> distributionLevels [ $result ];
if ( $field == 'to_ids' ) $result = ( $result == 0 ? 'No' : 'Yes' );
if ( $field == 'timestamp' ) {
if ( isset ( $result )) $result = date ( 'Y-m-d' , $result );
else echo ' ' ;
}
$this -> set ( 'value' , $result );
$this -> layout = 'ajax' ;
$this -> render ( 'ajax/attributeViewFieldForm' );
}
public function fetchEditForm ( $id , $field = null ) {
$validFields = array ( 'value' , 'comment' , 'type' , 'category' , 'to_ids' , 'distribution' );
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.' );
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
$fields = array ( 'id' , 'distribution' , 'event_id' );
$additionalFieldsToLoad = $field ;
if ( $field == 'category' || $field == 'type' ) {
$fields [] = 'type' ;
$fields [] = 'category' ;
} else {
$fields [] = $field ;
}
$attribute = $this -> Attribute -> find ( 'first' , array (
'recursive' => - 1 ,
'conditions' => array ( 'Attribute.id' => $id ),
'fields' => $fields ,
'contain' => array (
'Event' => array (
'fields' => array ( 'distribution' , 'id' , 'user_id' , 'orgc' ),
)
)
));
if ( ! $this -> _isSiteAdmin ()) {
//
2014-05-07 17:16:19 +02:00
if ( $attribute [ 'Event' ][ 'orgc' ] == $this -> Auth -> user ( 'org' )
&& (( $this -> userRole [ 'perm_modify' ] && $attribute [ 'Event' ][ 'user_id' ] != $this -> Auth -> user ( 'id' ))
|| $this -> userRole [ 'perm_modify_org' ])) {
2014-04-17 11:44:40 +02:00
// Allow the edit
} else {
throw new NotFoundException ( __ ( 'Invalid attribute' ));
}
}
$this -> layout = 'ajax' ;
if ( $field == 'distribution' ) $this -> set ( 'distributionLevels' , $this -> Attribute -> distributionLevels );
if ( $field == 'category' ) {
$typeCategory = array ();
foreach ( $this -> Attribute -> categoryDefinitions as $k => $category ) {
foreach ( $category [ 'types' ] as $type ) {
$typeCategory [ $type ][] = $k ;
}
}
$this -> set ( 'typeCategory' , $typeCategory );
}
if ( $field == 'type' ) {
$this -> set ( 'categoryDefinitions' , $this -> Attribute -> categoryDefinitions );
}
$this -> set ( 'object' , $attribute [ 'Attribute' ]);
$fieldURL = ucfirst ( $field );
$this -> render ( 'ajax/attributeEdit' . $fieldURL . 'Form' );
}
2014-07-19 15:09:37 +02:00
public function attributeReplace ( $id ) {
if ( ! $this -> userRole [ 'perm_add' ]) {
throw new MethodNotAllowedException ( 'Event not found or you don\'t have permissions to create attributes' );
}
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'Event.id' => $id ),
'fields' => array ( 'id' , 'orgc' , 'distribution' ),
'recursive' => - 1
));
if ( empty ( $event ) || ( ! $this -> _isSiteAdmin () && ( $event [ 'Event' ][ 'orgc' ] != $this -> Auth -> user ( 'org' ) || ! $this -> userRole [ 'perm_add' ]))) 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 );
// combobos for categories
$categories = $this -> Attribute -> validate [ 'category' ][ 'rule' ][ 1 ];
array_pop ( $categories );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
$this -> set ( 'categories' , compact ( 'categories' ));
$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' ) != $event [ 'Event' ][ 'orgc' ] && ! $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 );
foreach ( $newValues as & $value ) {
$value = trim ( $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.' ;
2014-08-14 14:08:55 +02:00
$event = $this -> Attribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'Event.id' => $id ),
'recursive' => - 1
));
$event [ 'Event' ][ 'published' ] = 0 ;
2014-12-10 14:08:08 +01:00
$date = new DateTime ();
$event [ 'Event' ][ 'timestamp' ] = $date -> getTimestamp ();
2014-08-14 14:08:55 +02:00
$this -> Attribute -> Event -> save ( $event );
2014-07-19 15:09:37 +02:00
} 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 ));
else return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'errors' => $message )), 'status' => 200 ));
}
}
private function __checkCountForOne ( $number ) {
if ( $number != 1 ) return 's' ;
return '' ;
}
2015-08-07 12:04:44 +02:00
// download a sample by passing along an md5
2015-08-07 16:10:40 +02:00
public function downloadSample ( $hash = false , $allSamples = false , $eventID = false ) {
2015-08-07 12:04:44 +02:00
if ( ! $this -> userRole [ 'perm_auth' ]) throw new MethodNotAllowedException ( 'This functionality requires API key access.' );
//if (!$this->request->is('post')) throw new MethodNotAllowedException('Please POST the samples as described on the automation page.');
$isJson = false ;
$error = false ;
if ( $this -> response -> type () === 'application/json' ) {
$isJson = true ;
$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' ];
2015-08-07 16:10:40 +02:00
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 ;
2015-08-07 12:04:44 +02:00
2015-08-07 16:10:40 +02:00
$simpleFalse = array ( 'hash' , 'allSamples' , 'eventID' );
foreach ( $simpleFalse as $sF ) {
if ( ${$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
if ( $hash ) $validTypes = $this -> Attribute -> resolveHashType ( $hash );
2015-08-07 12:04:44 +02:00
$types = array ();
2015-08-24 13:29:25 +02:00
if ( $hash ) {
if ( $allSamples ) {
2015-08-07 16:10:40 +02:00
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 )) {
$types = array ( 'malware-sample' , 'filename|md5' );
$searchConditions = array ( 'AND' => array ( 'LOWER(Attribute.value2) LIKE' => strtolower ( $hash )));
2015-08-07 12:04:44 +02:00
}
}
}
2015-08-07 16:10:40 +02:00
if ( ! empty ( $eventID )) $searchConditions [ 'AND' ][] = array ( 'Event.id' => $eventID );
2015-08-07 12:04:44 +02:00
if ( empty ( $error )) {
$distributionConditions = array ();
if ( ! $this -> _isSiteAdmin ()) {
$distributionConditions = array ( " OR " =>
array (
array ( 'Event.org =' => $this -> Auth -> user ( 'org' )),
array ( " AND " =>
array ( 'Event.org !=' => $this -> Auth -> user ( 'org' )),
array ( 'Event.distribution !=' => 0 ),
array ( 'Attribute.distribution !=' => 0 ),
Configure :: read ( 'MISP.unpublishedprivate' ) ? array ( 'Event.published =' => 1 ) : array (),
)
)
);
}
$attributes = $this -> Attribute -> find ( 'all' , array (
'recursive' => - 1 ,
'contain' => array ( 'Event' ),
'fields' => array ( 'Attribute.event_id' , 'Attribute.id' , 'Attribute.value1' , 'Attribute.value2' , 'Event.info' ),
'conditions' => array (
'AND' => array (
$searchConditions ,
$distributionConditions ,
array ( 'Attribute.type' => 'malware-sample' )
))));
2015-08-07 16:10:40 +02:00
if ( empty ( $attributes )) $error = 'No hits with the given parameters.' ;
2015-08-07 12:04:44 +02:00
$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 ) {
2015-08-07 16:10:40 +02:00
$this -> set ( 'message' , $error );
$this -> set ( '_serialize' , array ( 'message' ));
2015-08-07 12:04:44 +02:00
} else {
$this -> set ( 'result' , $results );
$this -> set ( '_serialize' , array ( 'result' ));
}
} else {
2015-08-07 16:10:40 +02:00
$this -> set ( 'message' , $error );
$this -> set ( '_serialize' , array ( 'message' ));
2015-08-07 12:04:44 +02:00
}
}
2013-03-04 18:05:17 +01:00
}