2013-04-25 14:04:08 +02:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
App :: uses ( 'Folder' , 'Utility' );
App :: uses ( 'File' , 'Utility' );
2020-05-05 15:23:26 +02:00
App :: uses ( 'AttachmentTool' , 'Tools' );
2013-04-25 14:04:08 +02:00
2020-07-24 15:57:35 +02:00
/**
* @ property ShadowAttribute $ShadowAttribute
*/
2018-07-19 11:48:22 +02:00
class ShadowAttributesController extends AppController
{
public $components = array ( 'Acl' , 'Security' , 'RequestHandler' , 'Email' );
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
public $paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 ,
);
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
public $helpers = array ( 'Js' => array ( 'Jquery' ));
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
public function beforeFilter ()
{
parent :: beforeFilter ();
$this -> set ( 'title_for_layout' , 'Proposals' );
$this -> Security -> validatePost = true ;
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
// convert uuid to id if present in the url, and overwrite id field
if ( isset ( $this -> params -> query [ 'uuid' ])) {
$params = array (
2020-07-24 15:57:35 +02:00
'conditions' => array ( 'ShadowAttribute.uuid' => $this -> params -> query [ 'uuid' ]),
'recursive' => 0 ,
'fields' => 'ShadowAttribute.id'
);
2018-07-19 11:48:22 +02:00
$result = $this -> ShadowAttribute -> find ( 'first' , $params );
if ( isset ( $result [ 'ShadowAttribute' ]) && isset ( $result [ 'ShadowAttribute' ][ 'id' ])) {
$id = $result [ 'ShadowAttribute' ][ '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
2018-07-19 11:48:22 +02:00
private function __accept ( $id )
{
$this -> loadModel ( 'Attribute' );
$this -> Attribute -> Behaviors -> detach ( 'SysLogLogable.SysLogLogable' );
$shadow = $this -> ShadowAttribute -> find (
'first' ,
array (
'recursive' => - 1 ,
'conditions' => array (
'ShadowAttribute.id' => $id ,
'deleted' => 0
),
)
);
if ( empty ( $shadow )) {
return array ( 'false' => true , 'errors' => 'Proposal not found or you are not authorised to accept it.' );
}
2019-03-05 12:24:56 +01:00
$this -> ShadowAttribute -> publishKafkaNotification ( 'shadow_attribute' , $shadow , 'accept' );
2018-07-19 11:48:22 +02:00
$shadow = $shadow [ 'ShadowAttribute' ];
2020-08-14 13:40:05 +02:00
if ( $this -> ShadowAttribute -> typeIsAttachment ( $shadow [ 'type' ]) && ! $shadow [ 'proposal_to_delete' ]) {
2018-07-19 11:48:22 +02:00
$encodedFile = $this -> ShadowAttribute -> base64EncodeAttachment ( $shadow );
$shadow [ 'data' ] = $encodedFile ;
}
// If the old_id is set to anything but 0 then we're dealing with a proposed edit to an existing attribute
if ( $shadow [ 'old_id' ] != 0 ) {
// Find the live attribute by the shadow attribute's uuid, so we can begin editing it
$this -> Attribute -> contain = 'Event' ;
$activeAttribute = $this -> Attribute -> findByUuid ( $shadow [ 'uuid' ]);
2013-04-25 14:04:08 +02:00
2020-07-24 15:57:35 +02:00
// Send those away that shouldn't be able to edit this
if ( ! $this -> __canModifyEvent ( $activeAttribute )) {
if ( $this -> _isRest ()) {
return array ( 'false' => true , 'errors' => 'Proposal not found or you are not authorised to accept it.' );
} else {
$this -> Flash -> error ( 'You don\'t have permission to do that' );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $shadow [ 'event_id' ]));
2018-07-19 11:48:22 +02:00
}
}
2020-07-24 15:57:35 +02:00
2018-07-19 11:48:22 +02:00
if ( isset ( $shadow [ 'proposal_to_delete' ]) && $shadow [ 'proposal_to_delete' ]) {
$this -> Attribute -> delete ( $activeAttribute [ 'Attribute' ][ 'id' ]);
} else {
// Update the live attribute with the shadow data
2019-12-16 13:36:01 +01:00
$fieldsToUpdate = array ( 'value1' , 'value2' , 'value' , 'type' , 'category' , 'comment' , 'to_ids' , 'first_seen' , 'last_seen' );
2018-07-19 11:48:22 +02:00
foreach ( $fieldsToUpdate as $f ) {
$activeAttribute [ 'Attribute' ][ $f ] = $shadow [ $f ];
}
2020-07-24 15:57:35 +02:00
$date = new DateTime ();
2018-07-19 11:48:22 +02:00
$activeAttribute [ 'Attribute' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> Attribute -> save ( $activeAttribute [ 'Attribute' ]);
}
$this -> ShadowAttribute -> setDeleted ( $id );
$this -> loadModel ( 'Event' );
$this -> Event -> Behaviors -> detach ( 'SysLogLogable.SysLogLogable' );
$this -> Event -> recursive = - 1 ;
// Unpublish the event, accepting a proposal is modifying the event after all. Also, reset the lock.
$event = $this -> Event -> read ( null , $activeAttribute [ 'Attribute' ][ 'event_id' ]);
if ( ! $this -> _isRest ()) {
$this -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
}
$this -> Event -> unpublishEvent ( $activeAttribute [ 'Attribute' ][ 'event_id' ], true );
$this -> Log = ClassRegistry :: init ( 'Log' );
$this -> Log -> create ();
$this -> Log -> save ( array (
'org_id' => $this -> Auth -> user ( 'org_id' ),
'model' => 'ShadowAttribute' ,
'model_id' => $id ,
'email' => $this -> Auth -> user ( 'email' ),
'action' => 'accept' ,
'title' => 'Proposal (' . $shadow [ 'id' ] . ') of ' . $shadow [ 'org_id' ] . ' to Attribute (' . $shadow [ 'old_id' ] . ') of Event (' . $shadow [ 'event_id' ] . ') accepted - ' . $shadow [ 'category' ] . '/' . $shadow [ 'type' ] . ' ' . $shadow [ 'value' ],
));
return array ( 'saved' => true , 'success' => 'Proposed change accepted.' );
} else {
// If the old_id is set to 0, then we're dealing with a brand new proposed attribute
// The idea is to load the event that the new attribute will be attached to, create an attribute to it and set the distribution equal to that of the event
$toDeleteId = $shadow [ 'id' ];
$this -> loadModel ( 'Event' );
$this -> Event -> Behaviors -> detach ( 'SysLogLogable.SysLogLogable' );
$this -> Event -> recursive = - 1 ;
$event = $this -> Event -> read ( null , $shadow [ 'event_id' ]);
2016-06-04 01:08:16 +02:00
2020-07-24 15:57:35 +02:00
if ( ! $this -> __canModifyEvent ( $event )) {
$this -> Flash -> error ( 'You don\'t have permission to do that' );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
2018-07-19 11:48:22 +02:00
}
if ( ! $this -> _isRest ()) {
$this -> Event -> insertLock ( $this -> Auth -> user (), $event [ 'Event' ][ 'id' ]);
}
$shadowForLog = $shadow ;
// Stuff that we won't use in its current form for the attribute
unset ( $shadow [ 'email' ], $shadow [ 'org_id' ], $shadow [ 'id' ], $shadow [ 'old_id' ]);
$attribute = $shadow ;
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// set the distribution equal to that of the event
$attribute [ 'distribution' ] = 5 ;
$this -> Attribute -> create ();
$this -> Attribute -> save ( $attribute );
$this -> ShadowAttribute -> setDeleted ( $toDeleteId );
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
if ( $this -> Auth -> user ( 'org_id' ) == $event [ 'Event' ][ 'orgc_id' ]) {
$this -> Event -> unpublishEvent ( $shadow [ 'event_id' ], true );
$event [ 'Event' ][ 'proposal_email_lock' ] = 0 ;
} else {
$this -> Event -> unpublishEvent ( $shadow [ 'event_id' ]);
}
$this -> Log = ClassRegistry :: init ( 'Log' );
$this -> Log -> create ();
$this -> Log -> save ( array (
'org_id' => $this -> Auth -> user ( 'org_id' ),
'model' => 'ShadowAttribute' ,
'model_id' => $id ,
'email' => $this -> Auth -> user ( 'email' ),
'action' => 'accept' ,
'title' => 'Proposal (' . $shadowForLog [ 'id' ] . ') of ' . $shadowForLog [ 'org_id' ] . ' to Event(' . $shadowForLog [ 'event_id' ] . ') accepted' ,
'change' => null ,
));
return array ( 'saved' => true , 'success' => 'Proposal accepted.' );
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// Accept a proposed edit and update the attribute
public function accept ( $id = null )
{
if ( ! $this -> request -> is ( 'post' )) {
throw new MethodNotAllowedException ();
}
$response = $this -> __accept ( $id );
if ( $this -> _isRest ()) {
if ( isset ( $response [ 'success' ])) {
$response [ 'check_publish' ] = true ;
$this -> set ( 'name' , $response [ 'success' ]);
$this -> set ( 'message' , $response [ 'success' ]);
2020-08-17 17:28:04 +02:00
$this -> set ( 'url' , $this -> baseurl . '/shadow_attributes/accept/' . $id );
2018-07-19 11:48:22 +02:00
$this -> set ( '_serialize' , array ( 'name' , 'message' , 'url' ));
} else {
throw new MethodNotAllowedException ( $response [ 'errors' ]);
}
} else {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( $response ), 'status' => 200 , 'type' => 'json' ));
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
private function __discard ( $id )
{
$sa = $this -> ShadowAttribute -> find (
'first' ,
array (
'recursive' => - 1 ,
2020-07-24 15:57:35 +02:00
'contain' => 'Event' ,
2018-07-19 11:48:22 +02:00
'conditions' => array (
'ShadowAttribute.id' => $id ,
'deleted' => 0
),
)
);
if ( empty ( $sa )) {
return false ;
}
2020-08-05 19:04:37 +02:00
// Just auth of proposal or user that can edit event can discard proposal.
if ( ! $this -> __canModifyEvent ( $sa ) && $this -> Auth -> user ( 'email' ) !== $sa [ 'ShadowAttribute' ][ 'email' ]) {
2020-07-24 15:57:35 +02:00
return false ;
2018-07-19 11:48:22 +02:00
}
2020-07-24 15:57:35 +02:00
$this -> ShadowAttribute -> publishKafkaNotification ( 'shadow_attribute' , $sa , 'discard' );
2018-07-19 11:48:22 +02:00
if ( $this -> ShadowAttribute -> setDeleted ( $id )) {
2020-07-24 15:57:35 +02:00
if ( $this -> Auth -> user ( 'org_id' ) == $sa [ 'Event' ][ 'orgc_id' ]) {
$this -> ShadowAttribute -> setProposalLock ( $sa [ 'Event' ][ 'id' ], false );
2018-07-19 11:48:22 +02:00
}
2020-07-24 15:57:35 +02:00
$logTitle = " Proposal ( { $sa [ 'ShadowAttribute' ][ 'id' ] } ) of { $sa [ 'ShadowAttribute' ][ 'org_id' ] } discarded - { $sa [ 'ShadowAttribute' ][ 'category' ] } / { $sa [ 'ShadowAttribute' ][ 'type' ] } { $sa [ 'ShadowAttribute' ][ 'value' ] } " ;
2018-07-19 11:48:22 +02:00
$this -> Log = ClassRegistry :: init ( 'Log' );
2020-08-05 19:04:37 +02:00
$this -> Log -> createLogEntry ( $this -> Auth -> user (), 'discard' , 'ShadowAttribute' , $id , $logTitle );
2018-07-19 11:48:22 +02:00
return true ;
}
return false ;
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// This method will discard a proposed change. Users that can delete the proposals are the publishing users of the org that created the event and of the ones that created the proposal - in addition to site admins of course
public function discard ( $id = null )
{
if ( $this -> request -> is ( 'post' )) {
if ( $this -> __discard ( $id )) {
if ( $this -> _isRest ()) {
$this -> set ( 'name' , 'Proposal discarded.' );
$this -> set ( 'message' , 'Proposal discarded.' );
2020-08-17 17:28:04 +02:00
$this -> set ( 'url' , $this -> baseurl . '/shadow_attributes/discard/' . $id );
2018-07-19 11:48:22 +02:00
$this -> set ( '_serialize' , array ( 'name' , 'message' , 'url' ));
} else {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Proposal discarded.' )), 'status' => 200 , 'type' => 'json' ));
}
} else {
if ( $this -> _isRest ()) {
2020-07-24 15:57:35 +02:00
throw new InternalErrorException ( __ ( 'Could not discard proposal.' ));
2018-07-19 11:48:22 +02:00
} else {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'Could not discard proposal.' )), 'status' => 200 , 'type' => 'json' ));
}
}
} else {
if ( ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ();
}
$this -> autoRender = false ;
$this -> set ( 'id' , $id );
$shadowAttribute = $this -> ShadowAttribute -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'event_id' ),
));
$this -> set ( 'event_id' , $shadowAttribute [ 'ShadowAttribute' ][ 'event_id' ]);
$this -> render ( 'ajax/shadowAttributeConfirmationForm' );
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function add ( $eventId )
{
if ( $this -> request -> is ( 'ajax' )) {
$this -> set ( 'ajax' , true );
$this -> layout = 'ajax' ;
} else {
$this -> set ( 'ajax' , false );
}
2020-07-24 15:57:35 +02:00
$event = $this -> ShadowAttribute -> Event -> fetchSimpleEvent ( $this -> Auth -> user (), $eventId );
2018-07-19 11:48:22 +02:00
if ( empty ( $event )) {
throw new NotFoundException ( __ ( 'Invalid Event' ));
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'post' )) {
if ( isset ( $this -> request -> data [ 'request' ])) {
$this -> request -> data = $this -> request -> data [ 'request' ];
}
// rearrange the request in case someone didn't RTFM
$invalidNames = array ( 'Attribute' , 'Proposal' );
foreach ( $invalidNames as $iN ) {
if ( isset ( $this -> request -> data [ $iN ]) && ! isset ( $this -> request -> data [ 'ShadowAttribute' ])) {
$this -> request -> data [ 'ShadowAttribute' ] = $this -> request -> data [ $iN ];
}
}
if ( ! isset ( $this -> request -> data [ 'ShadowAttribute' ])) {
$this -> request -> data = array ( 'ShadowAttribute' => $this -> request -> data );
}
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
}
// Give error if someone tried to submit an attribute with type 'attachment' or 'malware-sample'.
// TODO change behavior attachment options - this is bad ... it should rather by a messagebox or should be filtered out on the view level
if ( isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'type' ]) && $this -> ShadowAttribute -> typeIsAttachment ( $this -> request -> data [ 'ShadowAttribute' ][ 'type' ]) && ! $this -> _isRest ()) {
$this -> Flash -> error ( __ ( 'Attribute has not been added: attachments are added by "Add attachment" button' , true ), 'default' , array (), 'error' );
2020-07-24 15:57:35 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $event [ 'Event' ][ 'id' ]));
2018-07-19 11:48:22 +02:00
}
2020-07-24 15:57:35 +02:00
$this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] = $event [ 'Event' ][ 'id' ];
2018-07-19 11:48:22 +02:00
//
// multiple attributes in batch import
//
if ( ! $this -> _isRest () && ( isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'batch_import' ]) && $this -> request -> data [ 'ShadowAttribute' ][ 'batch_import' ] == 1 )) {
// make array from value field
$attributes = explode ( " \n " , $this -> request -> data [ 'ShadowAttribute' ][ 'value' ]);
2019-02-10 13:08:12 +01:00
$fails = " " ; // will be used to keep a list of the lines that failed or succeeded
2018-07-19 11:48:22 +02:00
$successes = " " ;
// TODO loopholes
// 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 -> ShadowAttribute -> create ();
$this -> request -> data [ 'ShadowAttribute' ][ 'value' ] = $attribute ; // set the value as the content of the single line
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$this -> request -> data [ 'ShadowAttribute' ][ 'org_id' ] = $this -> Auth -> user ( 'org_id' );
$this -> request -> data [ 'ShadowAttribute' ][ 'event_uuid' ] = $event [ 'Event' ][ 'uuid' ];
$this -> request -> data [ 'ShadowAttribute' ][ 'event_org_id' ] = $event [ 'Event' ][ 'org_id' ];
// TODO loopholes
// there seems to be a loophole in MISP here
// be it an create and not an update
$this -> ShadowAttribute -> id = null ;
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
$successes .= " " . ( $key + 1 );
} else {
$fails .= " " . ( $key + 1 );
}
}
// we added all the attributes
if ( $this -> request -> is ( 'ajax' )) {
// handle it if some of them failed!
if ( $fails ) {
$error_message = 'The lines' . $fails . ' could not be saved. Please, try again.' ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $error_message )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true )), 'status' => 200 , 'type' => 'json' ));
}
} else {
if ( $fails ) {
// list the ones that failed
if ( ! CakeSession :: read ( 'Message.flash' )) {
$this -> Flash -> error ( __ ( 'The lines' . $fails . ' could not be saved. Please, try again.' , true ));
} else {
$existingFlash = CakeSession :: read ( 'Message.flash' );
$this -> Flash -> error ( __ ( 'The lines' . $fails . ' could not be saved. ' . $existingFlash [ 'message' ], true ));
}
}
if ( $successes ) {
// list the ones that succeeded
$emailResult = " " ;
2020-07-24 15:57:35 +02:00
if ( ! $this -> ShadowAttribute -> sendProposalAlertEmail ( $event [ 'Event' ][ 'id' ]) === false ) {
2018-07-19 11:48:22 +02:00
$emailResult = " but nobody from the owner organisation could be notified by e-mail. " ;
}
$this -> Flash -> success ( __ ( 'The lines' . $successes . ' have been saved' . $emailResult , true ));
}
}
2015-10-30 13:39:12 +01:00
2018-07-19 11:48:22 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
} else {
//
// single attribute
//
// create the attribute
$this -> ShadowAttribute -> create ();
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$this -> request -> data [ 'ShadowAttribute' ][ 'org_id' ] = $this -> Auth -> user ( 'org_id' );
$this -> request -> data [ 'ShadowAttribute' ][ 'event_uuid' ] = $event [ 'Event' ][ 'uuid' ];
$this -> request -> data [ 'ShadowAttribute' ][ 'event_org_id' ] = $event [ 'Event' ][ 'org_id' ];
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
// list the ones that succeeded
$emailResult = " " ;
if ( ! isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'deleted' ]) || ! $this -> request -> data [ 'ShadowAttribute' ][ 'deleted' ]) {
if ( ! $this -> ShadowAttribute -> sendProposalAlertEmail ( $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ])) {
$emailResult = " but sending out the alert e-mails has failed for at least one recipient. " ;
}
}
// inform the user and redirect
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'Proposal added' . $emailResult )), 'status' => 200 , 'type' => 'json' ));
} elseif ( $this -> _isRest ()) {
$sa = $this -> ShadowAttribute -> find (
'first' ,
array (
'conditions' => array ( 'ShadowAttribute.id' => $this -> ShadowAttribute -> id ),
'recursive' => - 1 ,
2019-06-24 10:28:55 +02:00
'fields' => array ( 'id' , 'old_id' , 'event_id' , 'type' , 'category' , 'value' , 'comment' , 'to_ids' , 'uuid' , 'event_org_id' , 'email' , 'deleted' , 'timestamp' , 'first_seen' , 'last_seen' )
2018-07-19 11:48:22 +02:00
)
);
$this -> set ( 'ShadowAttribute' , $sa [ 'ShadowAttribute' ]);
$this -> set ( '_serialize' , array ( 'ShadowAttribute' ));
} else {
$this -> Flash -> success ( __ ( 'The proposal has been saved' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
} else {
if ( $this -> request -> is ( 'ajax' )) {
$this -> autoRender = false ;
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => $this -> ShadowAttribute -> validationErrors )), 'status' => 200 , 'type' => 'json' ));
} elseif ( $this -> _isRest ()) {
$message = '' ;
foreach ( $this -> ShadowAttribute -> validationErrors as $k => $v ) {
$message .= '[' . $k . ']: ' . $v [ 0 ] . PHP_EOL ;
}
throw new NotFoundException ( __ ( 'Could not save the proposal. Errors: %s' , $message ));
} else {
$this -> Flash -> error ( __ ( 'The proposal could not be saved. Please, try again.' ));
}
}
}
} else {
// set the event_id in the form
2020-07-24 15:57:35 +02:00
$this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] = $event [ 'Event' ][ 'id' ];
2018-07-19 11:48:22 +02:00
}
2020-07-24 15:57:35 +02:00
$this -> set ( 'event_id' , $event [ 'Event' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
// combobox for types
$types = array_keys ( $this -> ShadowAttribute -> typeDefinitions );
foreach ( $types as $key => $value ) {
if ( in_array ( $value , array ( 'malware-sample' , 'attachment' ))) {
unset ( $types [ $key ]);
}
}
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = array_keys ( $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
2020-07-04 10:38:50 +02:00
$this -> set ( 'categories' , $categories );
2020-07-23 17:37:11 +02:00
$fieldDesc = [ 'category' => [], 'type' => []];
foreach ( $this -> ShadowAttribute -> categoryDefinitions as $key => $value ) {
$fieldDesc [ 'category' ][ $key ] = isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ];
2018-07-19 11:48:22 +02:00
}
2020-07-23 17:37:11 +02:00
foreach ( $this -> ShadowAttribute -> typeDefinitions as $key => $value ) {
$fieldDesc [ 'type' ][ $key ] = isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ];
2018-07-19 11:48:22 +02:00
}
2020-07-23 17:37:11 +02:00
$this -> set ( 'fieldDesc' , $fieldDesc );
2018-07-19 11:48:22 +02:00
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> categoryDefinitions );
}
2013-04-25 14:04:08 +02:00
2020-08-05 19:05:10 +02:00
public function download ( $id )
2018-07-19 11:48:22 +02:00
{
2020-07-24 15:57:35 +02:00
$conditions = $this -> ShadowAttribute -> buildConditions ( $this -> Auth -> user ());
$conditions [ 'ShadowAttribute.id' ] = $id ;
$conditions [ 'ShadowAttribute.deleted' ] = 0 ;
2018-07-19 11:48:22 +02:00
$sa = $this -> ShadowAttribute -> find ( 'first' , array (
'recursive' => - 1 ,
2020-08-05 19:05:10 +02:00
'contain' => [ 'Event' , 'Attribute' ], // required because of conditions
2020-07-24 15:57:35 +02:00
'conditions' => $conditions ,
2018-07-19 11:48:22 +02:00
));
2020-07-24 15:57:35 +02:00
if ( ! $sa ) {
throw new NotFoundException ( __ ( 'Invalid Proposal' ));
2018-07-19 11:48:22 +02:00
}
$this -> __downloadAttachment ( $sa [ 'ShadowAttribute' ]);
}
2013-04-25 14:04:08 +02:00
2020-08-13 15:58:42 +02:00
private function __downloadAttachment ( array $shadowAttribute )
2018-07-19 11:48:22 +02:00
{
2020-08-13 15:58:42 +02:00
$file = $this -> ShadowAttribute -> getAttachmentFile ( $shadowAttribute );
2020-05-05 15:23:26 +02:00
2020-08-13 15:58:42 +02:00
if ( 'attachment' === $shadowAttribute [ 'type' ]) {
2018-07-19 11:48:22 +02:00
$filename = $shadowAttribute [ 'value' ];
$fileExt = pathinfo ( $filename , PATHINFO_EXTENSION );
$filename = substr ( $filename , 0 , strlen ( $filename ) - strlen ( $fileExt ) - 1 );
2020-08-13 15:58:42 +02:00
} elseif ( 'malware-sample' === $shadowAttribute [ 'type' ]) {
2018-07-19 11:48:22 +02:00
$filenameHash = explode ( '|' , $shadowAttribute [ 'value' ]);
$filename = substr ( $filenameHash [ 0 ], strrpos ( $filenameHash [ 0 ], '\\' ));
$fileExt = " zip " ;
} else {
throw new NotFoundException ( __ ( 'Proposal not an attachment or malware-sample' ));
}
$this -> autoRender = false ;
$this -> response -> type ( $fileExt );
2020-05-05 15:23:26 +02:00
$this -> response -> file ( $file -> path , array ( 'download' => true , 'name' => $filename . '.' . $fileExt ));
2018-07-19 11:48:22 +02:00
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
public function add_attachment ( $eventId = null )
{
2020-07-24 15:57:35 +02:00
$event = $this -> ShadowAttribute -> Event -> fetchSimpleEvent ( $this -> Auth -> user (), $eventId );
2018-07-19 11:48:22 +02:00
if ( empty ( $event )) {
throw new NotFoundException ( __ ( 'Invalid Event' ));
}
if ( $this -> request -> is ( 'post' )) {
// Check if there were problems with the file upload
// only keep the last part of the filename, this should prevent directory attacks
$hashes = array ( 'md5' => 'malware-sample' , 'sha1' => 'filename|sha1' , 'sha256' => 'filename|sha256' );
$filename = basename ( $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'name' ]);
$tmpfile = new File ( $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'tmp_name' ]);
if (( isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'error' ]) && $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'error' ] == 0 ) ||
( ! empty ( $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'tmp_name' ]) && $this -> request -> data [ 'ShadowAttribute' ][ 'value' ][ 'tmp_name' ] != 'none' )
) {
if ( ! is_uploaded_file ( $tmpfile -> path )) {
throw new InternalErrorException ( __ ( 'PHP says file was not uploaded. Are you attacking me?' ));
}
} else {
2020-07-24 15:57:35 +02:00
$this -> Flash -> error ( __ ( 'There was a problem to upload the file.' ));
2018-07-19 11:48:22 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
$fails = array ();
$completeFail = false ;
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
if ( $this -> request -> data [ 'ShadowAttribute' ][ 'malware' ]) {
$result = $this -> ShadowAttribute -> Event -> Attribute -> handleMaliciousBase64 ( $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ], $filename , base64_encode ( $tmpfile -> read ()), array_keys ( $hashes ));
if ( ! $result [ 'success' ]) {
2020-07-24 15:57:35 +02:00
$this -> Flash -> error ( __ ( 'There was a problem to upload the file.' ), 'default' , array (), 'error' );
2018-07-19 11:48:22 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
foreach ( $hashes as $hash => $typeName ) {
if ( ! $result [ $hash ]) {
continue ;
}
$shadowAttribute = array (
'ShadowAttribute' => array (
'value' => $filename . '|' . $result [ $hash ],
'category' => $this -> request -> data [ 'ShadowAttribute' ][ 'category' ],
'type' => $typeName ,
'event_id' => $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ],
'comment' => $this -> request -> data [ 'ShadowAttribute' ][ 'comment' ],
'to_ids' => 1 ,
'email' => $this -> Auth -> user ( 'email' ),
'org_id' => $this -> Auth -> user ( 'org_id' ),
'event_uuid' => $event [ 'Event' ][ 'uuid' ],
'event_org_id' => $event [ 'Event' ][ 'orgc_id' ],
)
);
if ( $hash == 'md5' ) {
$shadowAttribute [ 'ShadowAttribute' ][ 'data' ] = $result [ 'data' ];
}
$this -> ShadowAttribute -> create ();
$r = $this -> ShadowAttribute -> save ( $shadowAttribute );
if ( $r == false ) {
$fails [] = array ( $typeName );
}
if ( count ( $fails ) == count ( $hashes )) {
$completeFail = true ;
}
}
} else {
$shadowAttribute = array (
'ShadowAttribute' => array (
'value' => $filename ,
'category' => $this -> request -> data [ 'ShadowAttribute' ][ 'category' ],
'type' => 'attachment' ,
'event_id' => $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ],
'comment' => $this -> request -> data [ 'ShadowAttribute' ][ 'comment' ],
'data' => base64_encode ( $tmpfile -> read ()),
'to_ids' => 0 ,
'email' => $this -> Auth -> user ( 'email' ),
'org_id' => $this -> Auth -> user ( 'org_id' ),
'event_uuid' => $event [ 'Event' ][ 'uuid' ],
'event_org_id' => $event [ 'Event' ][ 'orgc_id' ],
)
);
$this -> ShadowAttribute -> create ();
$r = $this -> ShadowAttribute -> save ( $shadowAttribute );
if ( $r == false ) {
$fails [] = array ( 'attachment' );
$completeFail = true ;
}
}
if ( ! $completeFail ) {
if ( empty ( $fails )) {
$this -> Flash -> success ( __ ( 'The attachment has been uploaded' ));
} else {
$this -> Flash -> success ( __ ( 'The attachment has been uploaded, but some of the proposals could not be created. The failed proposals are: ' . implode ( ', ' , $fails )));
}
} else {
$this -> Flash -> error ( __ ( 'The attachment could not be saved, please contact your administrator.' ));
}
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
} else {
// set the event_id in the form
2020-07-24 15:57:35 +02:00
$this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] = $event [ 'Event' ][ 'id' ];
2018-07-19 11:48:22 +02:00
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// combobox for categories
$categories = array_keys ( $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
// just get them with attachments..
$selectedCategories = array ();
foreach ( $categories as $category ) {
if ( isset ( $this -> ShadowAttribute -> categoryDefinitions [ $category ])) {
$types = $this -> ShadowAttribute -> categoryDefinitions [ $category ][ 'types' ];
$alreadySet = false ;
foreach ( $types as $type ) {
if ( $this -> ShadowAttribute -> typeIsAttachment ( $type ) && ! $alreadySet ) {
// add to the whole..
$selectedCategories [] = $category ;
$alreadySet = true ;
}
}
}
}
$categories = $this -> _arrayToValuesIndexArray ( $selectedCategories );
$this -> set ( 'categories' , $categories );
foreach ( $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions as $key => $value ) {
$info [ 'category' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
foreach ( $this -> ShadowAttribute -> Event -> Attribute -> typeDefinitions as $key => $value ) {
$info [ 'type' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
$this -> set ( 'info' , $info );
$this -> set ( 'attrDescriptions' , $this -> ShadowAttribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> ShadowAttribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> categoryDefinitions );
2015-10-30 13:39:12 +01:00
2018-07-19 11:48:22 +02:00
$this -> set ( 'zippedDefinitions' , $this -> ShadowAttribute -> zippedDefinitions );
$this -> set ( 'uploadDefinitions' , $this -> ShadowAttribute -> uploadDefinitions );
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
// Propose an edit to an attribute
// Fields that can be used to edit an attribute when using the API:
// type, category, value, comment, to_ids
// if any of these fields is set, it will create a proposal
public function edit ( $id = null )
{
$existingAttribute = $this -> ShadowAttribute -> Event -> Attribute -> fetchAttributes ( $this -> Auth -> user (), array (
'contain' => array ( 'Event' => array ( 'fields' => array ( 'Event.id' , 'Event.orgc_id' , 'Event.org_id' , 'Event.distribution' , 'Event.uuid' ))),
2020-07-24 15:57:35 +02:00
'conditions' => $this -> __attributeIdToConditions ( $id ),
2018-07-19 11:48:22 +02:00
'flatten' => 1
));
if ( empty ( $existingAttribute )) {
2020-07-24 15:57:35 +02:00
throw new NotFoundException ( __ ( 'Invalid Attribute.' ));
2018-07-19 11:48:22 +02:00
}
$existingAttribute = $existingAttribute [ 0 ];
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
// Check if the attribute is an attachment, if yes, block the type and the value fields from being edited.
if ( 'attachment' == $existingAttribute [ 'Attribute' ][ 'type' ] || 'malware-sample' == $existingAttribute [ 'Attribute' ][ 'type' ]) {
$this -> set ( 'attachment' , true );
$attachment = true ;
} else {
$this -> set ( 'attachment' , false );
$attachment = false ;
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'post' ) || $this -> request -> is ( 'put' )) {
if ( isset ( $this -> request -> data [ 'request' ])) {
$this -> request -> data = $this -> request -> data [ 'request' ];
}
2019-07-29 17:10:21 +02:00
if ( ! isset ( $this -> request -> data [ 'ShadowAttribute' ])) {
$this -> request -> data [ 'ShadowAttribute' ] = $this -> request -> data ;
}
2018-07-19 11:48:22 +02:00
// rearrange the request in case someone didn't RTFM
$invalidNames = array ( 'Attribute' , 'Proposal' );
foreach ( $invalidNames as $iN ) {
if ( isset ( $this -> request -> data [ $iN ]) && ! isset ( $this -> request -> data [ 'ShadowAttribute' ])) {
$this -> request -> data [ 'ShadowAttribute' ] = $this -> request -> data [ $iN ];
}
}
if ( $attachment ) {
$fields = array (
'static' => array ( 'old_id' => 'Attribute.id' , 'uuid' => 'Attribute.uuid' , 'event_id' => 'Attribute.event_id' , 'event_uuid' => 'Event.uuid' , 'event_org_id' => 'Event.orgc_id' , 'category' => 'Attribute.category' , 'type' => 'Attribute.type' ),
2019-06-24 10:28:55 +02:00
'optional' => array ( 'value' , 'to_ids' , 'comment' , 'first_seen' , 'last_seen' )
2018-07-19 11:48:22 +02:00
);
} else {
$fields = array (
'static' => array ( 'old_id' => 'Attribute.id' , 'uuid' => 'Attribute.uuid' , 'event_id' => 'Attribute.event_id' , 'event_uuid' => 'Event.uuid' , 'event_org_id' => 'Event.orgc_id' ),
2019-06-24 10:28:55 +02:00
'optional' => array ( 'category' , 'type' , 'value' , 'to_ids' , 'comment' , 'first_seen' , 'last_seen' )
2018-07-19 11:48:22 +02:00
);
if ( $existingAttribute [ 'Attribute' ][ 'object_id' ]) {
unset ( $fields [ 'optional' ][ 'type' ]);
$fields [ 'static' ][ 'type' ] = 'Attribute.type' ;
}
}
foreach ( $fields [ 'static' ] as $k => $v ) {
$v = explode ( '.' , $v );
$this -> request -> data [ 'ShadowAttribute' ][ $k ] = $existingAttribute [ $v [ 0 ]][ $v [ 1 ]];
}
$validChangeMade = false ;
foreach ( $fields [ 'optional' ] as $v ) {
if ( ! isset ( $this -> request -> data [ 'ShadowAttribute' ][ $v ])) {
$this -> request -> data [ 'ShadowAttribute' ][ $v ] = $existingAttribute [ 'Attribute' ][ $v ];
} else {
$validChangeMade = true ;
}
}
if ( ! $validChangeMade ) {
throw new MethodNotAllowedException ( __ ( 'Invalid input.' ));
}
$this -> request -> data [ 'ShadowAttribute' ][ 'org_id' ] = $this -> Auth -> user ( 'org_id' );
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
$emailResult = " " ;
if ( ! isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'deleted' ]) || ! $this -> request -> data [ 'ShadowAttribute' ][ 'deleted' ]) {
if ( ! $this -> ShadowAttribute -> sendProposalAlertEmail ( $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ])) {
$emailResult = " but sending out the alert e-mails has failed for at least one recipient. " ;
}
}
if ( $this -> _isRest ()) {
$sa = $this -> ShadowAttribute -> find (
'first' ,
array (
'conditions' => array ( 'ShadowAttribute.id' => $this -> ShadowAttribute -> id ),
'recursive' => - 1 ,
2019-06-24 10:28:55 +02:00
'fields' => array ( 'id' , 'old_id' , 'event_id' , 'type' , 'category' , 'value' , 'comment' , 'to_ids' , 'uuid' , 'event_org_id' , 'email' , 'deleted' , 'timestamp' , 'first_seen' , 'last_seen' )
2018-07-19 11:48:22 +02:00
)
);
$this -> set ( 'ShadowAttribute' , $sa [ 'ShadowAttribute' ]);
$this -> set ( '_serialize' , array ( 'ShadowAttribute' ));
} else {
$this -> Flash -> success ( __ ( 'The proposed Attribute has been saved' . $emailResult ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $existingAttribute [ 'Attribute' ][ 'event_id' ]));
}
} else {
if ( $this -> _isRest ()) {
$message = '' ;
foreach ( $this -> ShadowAttribute -> validationErrors as $k => $v ) {
$message .= '[' . $k . ']: ' . $v [ 0 ] . PHP_EOL ;
}
2020-07-24 15:57:35 +02:00
throw new InternalErrorException ( __ ( 'Could not save the proposal. Errors: %s' , $message ));
2018-07-19 11:48:22 +02:00
} else {
$this -> Flash -> error ( __ ( 'The ShadowAttribute could not be saved. Please, try again.' ));
}
}
} else {
// Read the attribute that we're about to edit
$this -> ShadowAttribute -> create ();
$this -> request -> data [ 'ShadowAttribute' ] = $existingAttribute [ 'Attribute' ];
unset ( $this -> request -> data [ 'ShadowAttribute' ][ 'id' ]);
}
2013-04-25 14:04:08 +02:00
2018-07-19 11:48:22 +02:00
// combobox for types
$types = array_keys ( $this -> ShadowAttribute -> typeDefinitions );
foreach ( $types as $key => $value ) {
if ( in_array ( $value , array ( 'malware-sample' , 'attachment' ))) {
unset ( $types [ $key ]);
}
}
if ( $existingAttribute [ 'Attribute' ][ 'object_id' ]) {
$this -> set ( 'objectAttribute' , true );
} else {
$this -> set ( 'objectAttribute' , false );
}
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = $this -> _arrayToValuesIndexArray ( array_keys ( $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions ));
$categories = $this -> _arrayToValuesIndexArray ( $categories );
foreach ( $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions as $key => $value ) {
$info [ 'category' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
foreach ( $this -> ShadowAttribute -> Event -> Attribute -> typeDefinitions as $key => $value ) {
$info [ 'type' ][ $key ] = array ( 'key' => $key , 'desc' => isset ( $value [ 'formdesc' ]) ? $value [ 'formdesc' ] : $value [ 'desc' ]);
}
$categoryDefinitions = $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions ;
if ( $existingAttribute [ 'Attribute' ][ 'object_id' ]) {
foreach ( $categoryDefinitions as $k => $v ) {
if ( ! in_array ( $existingAttribute [ 'Attribute' ][ 'type' ], $v [ 'types' ])) {
unset ( $categoryDefinitions [ $k ]);
}
}
foreach ( $categories as $k => $v ) {
if ( ! isset ( $categoryDefinitions [ $k ])) {
unset ( $categories [ $k ]);
}
}
}
$this -> set ( 'categories' , $categories );
$this -> set ( 'info' , $info );
$this -> set ( 'attrDescriptions' , $this -> ShadowAttribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> ShadowAttribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> Event -> Attribute -> categoryDefinitions );
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function delete ( $id )
{
2020-07-14 12:34:29 +02:00
$existingAttribute = $this -> ShadowAttribute -> Event -> Attribute -> fetchAttributes (
$this -> Auth -> user (),
2020-07-24 15:57:35 +02:00
array ( 'conditions' => $this -> __attributeIdToConditions ( $id ), 'flatten' => true )
2020-07-14 12:34:29 +02:00
);
2018-07-19 11:48:22 +02:00
if ( $this -> request -> is ( 'post' )) {
if ( empty ( $existingAttribute )) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'Invalid Attribute.' )), 'status' => 200 , 'type' => 'json' ));
}
2019-01-31 15:10:18 +01:00
$existingAttribute = $existingAttribute [ 0 ];
2018-07-19 11:48:22 +02:00
$this -> ShadowAttribute -> create ();
$sa = array (
'old_id' => $existingAttribute [ 'Attribute' ][ 'id' ],
'uuid' => $existingAttribute [ 'Attribute' ][ 'uuid' ],
'event_id' => $existingAttribute [ 'Event' ][ 'id' ],
'event_uuid' => $existingAttribute [ 'Event' ][ 'uuid' ],
'event_org_id' => $existingAttribute [ 'Event' ][ 'orgc_id' ],
'category' => $existingAttribute [ 'Attribute' ][ 'category' ],
'type' => $existingAttribute [ 'Attribute' ][ 'type' ],
'to_ids' => $existingAttribute [ 'Attribute' ][ 'to_ids' ],
'value' => $existingAttribute [ 'Attribute' ][ 'value' ],
2019-06-24 10:28:55 +02:00
'first_seen' => $existingAttribute [ 'Attribute' ][ 'first_seen' ],
'last_seen' => $existingAttribute [ 'Attribute' ][ 'last_seen' ],
2018-07-19 11:48:22 +02:00
'email' => $this -> Auth -> user ( 'email' ),
'org_id' => $this -> Auth -> user ( 'org_id' ),
'proposal_to_delete' => true ,
);
if ( $this -> ShadowAttribute -> save ( $sa )) {
$emailResult = " " ;
if ( ! $this -> ShadowAttribute -> sendProposalAlertEmail ( $existingAttribute [ 'Event' ][ 'id' ])) {
$emailResult = " but sending out the alert e-mails has failed for at least one recipient. " ;
}
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => 'The proposal to delete the attribute has been saved' . $emailResult )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'Could not create proposal.' )), 'status' => 200 , 'type' => 'json' ));
}
} else {
if ( empty ( $existingAttribute )) {
2020-07-14 12:34:29 +02:00
throw new NotFoundException ( __ ( 'Invalid attribute' ));
2018-07-19 11:48:22 +02:00
}
2019-01-31 14:53:48 +01:00
$existingAttribute = $existingAttribute [ 0 ];
2020-07-24 15:57:35 +02:00
$this -> set ( 'id' , $existingAttribute [ 'Attribute' ][ 'id' ]);
2018-07-19 11:48:22 +02:00
$this -> set ( 'event_id' , $existingAttribute [ 'Attribute' ][ 'event_id' ]);
$this -> render ( 'ajax/deletionProposalConfirmationForm' );
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function view ( $id )
{
2020-07-24 15:57:35 +02:00
$conditions = $this -> ShadowAttribute -> buildConditions ( $this -> Auth -> user ());
$conditions [ 'ShadowAttribute.id' ] = $id ;
$conditions [ 'ShadowAttribute.deleted' ] = 0 ;
2018-07-19 11:48:22 +02:00
$sa = $this -> ShadowAttribute -> find ( 'first' , array (
2020-07-24 15:57:35 +02:00
'recursive' => - 1 ,
2020-08-05 19:05:10 +02:00
'contain' => [ 'Event' , 'Attribute' ], // required because of conditions
2020-07-24 15:57:35 +02:00
'fields' => array (
'ShadowAttribute.id' , 'ShadowAttribute.old_id' , 'ShadowAttribute.event_id' , 'ShadowAttribute.type' , 'ShadowAttribute.category' , 'ShadowAttribute.uuid' , 'ShadowAttribute.to_ids' , 'ShadowAttribute.value' , 'ShadowAttribute.comment' , 'ShadowAttribute.org_id' , 'ShadowAttribute.first_seen' , 'ShadowAttribute.last_seen' ,
),
'conditions' => $conditions ,
2018-07-19 11:48:22 +02:00
));
if ( empty ( $sa )) {
throw new NotFoundException ( __ ( 'Invalid proposal.' ));
}
$this -> set ( 'ShadowAttribute' , $sa [ 'ShadowAttribute' ]);
$this -> set ( '_serialize' , array ( 'ShadowAttribute' ));
}
2018-07-12 23:36:47 +02:00
2021-01-25 15:26:53 +01:00
public function viewPicture ( $id , $thumbnail = false )
{
$conditions [ 'ShadowAttribute.id' ] = $id ;
$conditions [ 'ShadowAttribute.type' ] = 'attachment' ;
$options = array (
'conditions' => $conditions ,
'includeAllTags' => false ,
'includeAttributeUuid' => true ,
'flatten' => true ,
'deleted' => [ 0 , 1 ]
);
$sa = $this -> ShadowAttribute -> find ( 'first' , array (
'recursive' => - 1 ,
'contain' => [ 'Event' , 'Attribute' ], // required because of conditions
'fields' => array (
'ShadowAttribute.id' , 'ShadowAttribute.old_id' , 'ShadowAttribute.event_id' , 'ShadowAttribute.type' , 'ShadowAttribute.category' , 'ShadowAttribute.uuid' , 'ShadowAttribute.to_ids' , 'ShadowAttribute.value' , 'ShadowAttribute.comment' , 'ShadowAttribute.org_id' , 'ShadowAttribute.first_seen' , 'ShadowAttribute.last_seen' ,
),
'conditions' => $conditions ,
));
if ( empty ( $sa )) {
throw new NotFoundException ( __ ( 'Invalid proposal.' ));
}
if ( ! $this -> ShadowAttribute -> Attribute -> isImage ( $sa [ 'ShadowAttribute' ])) {
throw new NotFoundException ( " ShadowAttribute is not an image. " );
}
if ( $this -> _isRest ()) {
if ( $this -> ShadowAttribute -> typeIsAttachment ( $sa [ 'ShadowAttribute' ][ 'type' ])) {
$encodedFile = $this -> ShadowAttribute -> base64EncodeAttachment ( $sa [ 'ShadowAttribute' ]);
$sa [ 'ShadowAttribute' ][ 'data' ] = $encodedFile ;
}
}
if ( $this -> _isRest ()) {
return $this -> RestResponse -> viewData ( $sa [ 'ShadowAttribute' ][ 'data' ], $this -> response -> type ());
} else {
$width = isset ( $this -> request -> params [ 'named' ][ 'width' ]) ? $this -> request -> params [ 'named' ][ 'width' ] : 200 ;
$height = isset ( $this -> request -> params [ 'named' ][ 'height' ]) ? $this -> request -> params [ 'named' ][ 'height' ] : 200 ;
$imageData = $this -> ShadowAttribute -> getPictureData ( $sa , $thumbnail , $width , $height );
$extension = pathinfo ( $sa [ 'ShadowAttribute' ][ 'value' ], PATHINFO_EXTENSION );
return new CakeResponse ( array ( 'body' => $imageData , 'type' => strtolower ( $extension )));
}
}
2018-07-19 11:48:22 +02:00
public function index ( $eventId = false )
{
2019-07-11 22:57:58 +02:00
$conditions = array ();
2018-07-19 11:48:22 +02:00
if ( isset ( $this -> request [ 'named' ][ 'all' ])) {
$all = $this -> request [ 'named' ][ 'all' ];
} else {
2019-07-29 11:38:20 +02:00
$all = 1 ;
2018-07-19 11:48:22 +02:00
}
2019-08-14 15:01:31 +02:00
$eventId = $this -> Toolbox -> findIdByUuid ( $this -> ShadowAttribute -> Event , $eventId , true );
2020-07-24 15:57:35 +02:00
if ( $eventId ) {
2018-07-19 11:48:22 +02:00
$conditions [ 'ShadowAttribute.event_id' ] = $eventId ;
}
2019-07-11 22:57:58 +02:00
$temp = $this -> ShadowAttribute -> buildConditions ( $this -> Auth -> user ());
if ( ! empty ( $temp )) {
$conditions [ 'AND' ][] = $temp ;
}
unset ( $temp );
if ( empty ( $all )) {
$conditions [ 'AND' ][] = array ( 'Event.orgc_id' => $this -> Auth -> user ( 'org_id' ));
}
if ( ! empty ( $this -> request [ 'named' ][ 'searchall' ])) {
2020-07-24 15:57:35 +02:00
$term = '%' . strtolower ( trim ( $this -> request [ 'named' ][ 'searchall' ])) . '%' ;
2019-07-11 22:57:58 +02:00
$conditions [ 'AND' ][] = array ( 'OR' => array (
2020-07-24 15:57:35 +02:00
'LOWER(ShadowAttribute.value1) LIKE' => $term ,
'LOWER(ShadowAttribute.value2) LIKE' => $term ,
'LOWER(ShadowAttribute.comment) LIKE' => $term ,
'LOWER(Event.info) LIKE' => $term ,
'LOWER(Org.name) LIKE' => $term ,
'LOWER(Org.uuid) LIKE' => $term ,
'LOWER(ShadowAttribute.uuid) LIKE' => $term ,
'LOWER(Event.uuid) LIKE' => $term ,
2018-07-19 11:48:22 +02:00
));
2019-07-11 22:57:58 +02:00
}
2019-07-12 16:03:08 +02:00
if ( isset ( $this -> request [ 'named' ][ 'deleted' ])) {
$conditions [ 'AND' ][] = array (
'ShadowAttribute.deleted' => $this -> request [ 'named' ][ 'deleted' ]
);
2020-08-16 13:31:31 +02:00
}
2019-07-11 22:57:58 +02:00
if ( ! empty ( $this -> request [ 'named' ][ 'timestamp' ])) {
$conditions [ 'AND' ][] = array (
'ShadowAttribute.timestamp >=' => $this -> request [ 'named' ][ 'timestamp' ]
);
}
2019-07-12 16:03:08 +02:00
if ( ! $this -> _isRest () && ! isset ( $this -> request [ 'named' ][ 'deleted' ])) {
$conditions [ 'AND' ][] = array ( 'ShadowAttribute.deleted' => 0 );
}
2019-07-11 22:57:58 +02:00
$params = array (
'conditions' => $conditions ,
2019-10-02 11:23:04 +02:00
'fields' => array ( 'ShadowAttribute.id' , 'ShadowAttribute.old_id' , 'ShadowAttribute.event_id' , 'ShadowAttribute.type' , 'ShadowAttribute.category' , 'ShadowAttribute.uuid' , 'ShadowAttribute.to_ids' , 'ShadowAttribute.value' , 'ShadowAttribute.comment' , 'ShadowAttribute.org_id' , 'ShadowAttribute.timestamp' , 'ShadowAttribute.first_seen' , 'ShadowAttribute.last_seen' ),
2019-07-11 22:57:58 +02:00
'contain' => array (
'Event' => array (
'fields' => array ( 'id' , 'org_id' , 'info' , 'orgc_id' , 'uuid' ),
2020-08-03 14:32:26 +02:00
'Orgc' => array ( 'fields' => array ( 'Orgc.name' , 'Orgc.id' , 'Orgc.uuid' ))
2019-07-11 22:57:58 +02:00
),
'Org' => array (
'fields' => array ( 'name' , 'uuid' ),
),
'Attribute' => array (
'fields' => array ( 'uuid' ),
'Object'
),
),
'recursive' => - 1
);
$simpleParams = array ( 'limit' , 'page' );
foreach ( $simpleParams as $simpleParam ) {
if ( ! empty ( $this -> request [ 'named' ][ $simpleParam ])) {
$params [ $simpleParam ] = $this -> request [ 'named' ][ $simpleParam ];
2018-07-19 11:48:22 +02:00
}
2019-07-11 22:57:58 +02:00
}
if ( isset ( $this -> request [ 'named' ][ 'sort' ])) {
$params [ 'order' ] = 'ShadowAttribute.' . $this -> request [ 'named' ][ 'sort' ];
if ( ! empty ( $this -> request [ 'named' ][ 'direction' ])) {
$direction = trim ( strtolower ( $this -> request [ 'named' ][ 'direction' ]));
$params [ 'order' ] .= ' ' . ( $direction === 'asc' ? 'ASC' : 'DESC' );
} else {
$params [ 'order' ] .= ' ASC' ;
2018-07-19 11:48:22 +02:00
}
2019-07-11 22:57:58 +02:00
}
if ( $this -> _isRest ()) {
$results = $this -> ShadowAttribute -> find ( 'all' , $params );
foreach ( $results as $k => $result ) {
$result [ 'ShadowAttribute' ][ 'org_uuid' ] = $result [ 'Org' ][ 'uuid' ];
if ( ! empty ( $result [ 'ShadowAttribute' ][ 'old_id' ])) {
$result [ 'ShadowAttribute' ][ 'old_uuid' ] = $result [ 'Attribute' ][ 'uuid' ];
}
$result [ 'ShadowAttribute' ][ 'event_uuid' ] = $result [ 'Event' ][ 'uuid' ];
$result [ 'ShadowAttribute' ][ 'Org' ] = $result [ 'Org' ];
if ( isset ( $result [ 'ShadowAttribute' ][ 'type' ]) && $this -> ShadowAttribute -> typeIsAttachment ( $result [ 'ShadowAttribute' ][ 'type' ]) && ! empty ( $result [ 'ShadowAttribute' ][ 'data' ])) {
$result = $result && $this -> ShadowAttribute -> saveBase64EncodedAttachment ( $result [ 'ShadowAttribute' ]);
}
$results [ $k ] = array ( 'ShadowAttribute' => $result [ 'ShadowAttribute' ]);
}
return $this -> RestResponse -> viewData ( $results , $this -> response -> type ());
2018-07-19 11:48:22 +02:00
} else {
2019-07-11 22:57:58 +02:00
$this -> paginate = $params ;
$results = $this -> paginate ();
foreach ( $results as $k => $result ) {
unset ( $results [ $k ][ 'Attribute' ]);
}
$this -> set ( 'shadowAttributes' , $results );
$this -> set ( 'all' , $all );
2018-07-19 11:48:22 +02:00
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function discardSelected ( $id )
{
if ( ! $this -> request -> is ( 'post' ) || ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ();
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// get a json object with a list of proposal IDs to be discarded
// check each of them and return a json object with the successful discards and the failed ones.
$ids = json_decode ( $this -> request -> data [ 'ShadowAttribute' ][ 'ids_discard' ]);
if ( ! $this -> _isSiteAdmin ()) {
$event = $this -> ShadowAttribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc_id' , 'user_id' )
));
2020-07-24 15:57:35 +02:00
if ( ! $event ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'Invalid event.' )), 'status' => 200 , 'type' => 'json' ));
}
if ( ! $this -> __canModifyEvent ( $event )) {
2018-07-19 11:48:22 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'You don\'t have permission to do that.' )), 'status' => 200 , 'type' => 'json' ));
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// find all attributes from the ID list that also match the provided event ID.
2020-07-24 15:57:35 +02:00
$shadowAttributes = $this -> ShadowAttribute -> find ( 'list' , array (
2018-07-19 11:48:22 +02:00
'recursive' => - 1 ,
'conditions' => array ( 'id' => $ids , 'event_id' => $id ),
2020-07-24 15:57:35 +02:00
'fields' => array ( 'id' )
2018-07-19 11:48:22 +02:00
));
$successes = array ();
2020-07-24 15:57:35 +02:00
foreach ( $shadowAttributes as $id ) {
if ( $this -> __discard ( $id )) {
$successes [] = $id ;
2018-07-19 11:48:22 +02:00
}
}
$fails = array_diff ( $ids , $successes );
$this -> autoRender = false ;
if ( count ( $fails ) == 0 && count ( $successes ) > 0 ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => count ( $successes ) . ' proposal' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted.' )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => count ( $successes ) . ' proposal' . ( count ( $successes ) != 1 ? 's' : '' ) . ' deleted, but ' . count ( $fails ) . ' proposal' . ( count ( $fails ) != 1 ? 's' : '' ) . ' could not be deleted.' )), 'status' => 200 , 'type' => 'json' ));
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function acceptSelected ( $id )
{
if ( ! $this -> request -> is ( 'post' ) || ! $this -> request -> is ( 'ajax' )) {
throw new MethodNotAllowedException ();
}
2015-06-25 11:51:36 +02:00
2018-07-19 11:48:22 +02:00
// get a json object with a list of proposal IDs to be accepted
// check each of them and return a json object with the successful accepts and the failed ones.
$ids = json_decode ( $this -> request -> data [ 'ShadowAttribute' ][ 'ids_accept' ]);
if ( ! $this -> _isSiteAdmin ()) {
$event = $this -> ShadowAttribute -> Event -> find ( 'first' , array (
'conditions' => array ( 'id' => $id ),
'recursive' => - 1 ,
'fields' => array ( 'id' , 'orgc_id' , 'user_id' )
));
2020-07-24 15:57:35 +02:00
if ( ! $event ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'Invalid event.' )), 'status' => 200 , 'type' => 'json' ));
}
if ( ! $this -> __canModifyEvent ( $event )) {
2018-07-19 11:48:22 +02:00
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'false' => true , 'errors' => 'You don\'t have permission to do that.' )), 'status' => 200 , 'type' => 'json' ));
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
// find all attributes from the ID list that also match the provided event ID.
2020-07-24 15:57:35 +02:00
$shadowAttributes = $this -> ShadowAttribute -> find ( 'list' , array (
2018-07-19 11:48:22 +02:00
'recursive' => - 1 ,
'conditions' => array ( 'id' => $ids , 'event_id' => $id ),
2020-07-24 15:57:35 +02:00
'fields' => array ( 'id' )
2018-07-19 11:48:22 +02:00
));
$successes = array ();
2020-07-24 15:57:35 +02:00
foreach ( $shadowAttributes as $shadowAttributeId ) {
$response = $this -> __accept ( $shadowAttributeId );
2018-07-19 11:48:22 +02:00
if ( isset ( $response [ 'saved' ])) {
2020-07-24 15:57:35 +02:00
$successes [] = $shadowAttributeId ;
2018-07-19 11:48:22 +02:00
}
}
$this -> ShadowAttribute -> Event -> unpublishEvent ( $id , true );
$fails = array_diff ( $ids , $successes );
$this -> autoRender = false ;
if ( count ( $fails ) == 0 && count ( $successes ) > 0 ) {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => true , 'success' => count ( $successes ) . ' proposal' . ( count ( $successes ) != 1 ? 's' : '' ) . ' accepted.' )), 'status' => 200 , 'type' => 'json' ));
} else {
return new CakeResponse ( array ( 'body' => json_encode ( array ( 'saved' => false , 'errors' => count ( $successes ) . ' proposal' . ( count ( $successes ) != 1 ? 's' : '' ) . ' accepted, but ' . count ( $fails ) . ' proposal' . ( count ( $fails ) != 1 ? 's' : '' ) . ' could not be accepted.' )), 'status' => 200 , 'type' => 'json' ));
}
}
2016-06-04 01:08:16 +02:00
2018-07-19 11:48:22 +02:00
public function generateCorrelation ()
{
if ( ! self :: _isSiteAdmin () || ! $this -> request -> is ( 'post' )) {
throw new NotFoundException ();
}
if ( ! Configure :: read ( 'MISP.background_jobs' )) {
$k = $this -> ShadowAttribute -> generateCorrelation ();
$this -> Flash -> success ( __ ( 'All done. ' . $k . ' proposals processed.' ));
$this -> redirect ( array ( 'controller' => 'pages' , 'action' => 'display' , 'administration' ));
} else {
$job = ClassRegistry :: init ( 'Job' );
$job -> create ();
$data = array (
'worker' => 'default' ,
'job_type' => 'generate proposal 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 ( 'jobGenerateShadowAttributeCorrelation' , $jobId )
);
$job -> saveField ( 'process_id' , $process_id );
$this -> Flash -> success ( __ ( 'Job queued. You can view the progress if you navigate to the active jobs view (administration -> jobs).' ));
$this -> redirect ( array ( 'controller' => 'pages' , 'action' => 'display' , 'administration' ));
}
}
2020-07-24 15:57:35 +02:00
private function __attributeIdToConditions ( $id )
{
if ( is_numeric ( $id )) {
$conditions = array ( 'Attribute.id' => $id );
} elseif ( Validation :: uuid ( $id )) {
$conditions = array ( 'Attribute.uuid' => $id );
} else {
throw new NotFoundException ( __ ( 'Invalid attribute ID.' ));
}
return $conditions ;
}
2013-04-25 14:04:08 +02:00
}