2013-04-25 14:04:08 +02:00
< ? php
App :: uses ( 'AppController' , 'Controller' );
App :: uses ( 'Folder' , 'Utility' );
App :: uses ( 'File' , 'Utility' );
/**
* ShadowAttributes Controller
*
* Handles requests to edit attributes , add attributes
*
* @ property ShadowAttribute $ShadowAttribute
*/
class ShadowAttributesController extends AppController {
2013-06-20 16:21:55 +02:00
public $components = array ( 'Acl' , 'Security' , 'RequestHandler' , 'Email' );
2013-04-25 14:04:08 +02:00
public $paginate = array (
'limit' => 60 ,
'maxLimit' => 9999 ,
);
public $helpers = array ( 'Js' => array ( 'Jquery' ));
public function beforeFilter () {
parent :: beforeFilter ();
$this -> Security -> validatePost = true ;
// convert uuid to id if present in the url, and overwrite id field
if ( isset ( $this -> params -> query [ 'uuid' ])) {
$params = array (
'conditions' => array ( 'ShadowAttribute.uuid' => $this -> params -> query [ 'uuid' ]),
'recursive' => 0 ,
'fields' => 'ShadowAttribute.id'
);
$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
}
}
// if not admin or own org, check private as well..
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-04-25 14:04:08 +02:00
$this -> paginate = Set :: merge ( $this -> paginate , array (
'conditions' =>
array ( 'OR' =>
array (
'Event.org =' => $this -> Auth -> user ( 'org' ),
'AND' => array (
2013-06-11 13:51:11 +02:00
'ShadowAttribute.org =' => $this -> Auth -> user ( 'org' ),
'Event.distribution >' => 0 ,
),
)
)));
2013-04-25 14:04:08 +02:00
}
}
/**
* accept method
*
* @ return void
*
*/
// Accept a proposed edit and update the attribute
public function accept ( $id = null ) {
if ( $this -> _isRest ()) {
throw new Exception ( 'This feature is limited to interactive users only.' );
}
$this -> loadModel ( 'Attribute' );
$this -> ShadowAttribute -> id = $id ;
$this -> ShadowAttribute -> recursive = - 1 ;
$this -> ShadowAttribute -> read ();
$shadow = $this -> ShadowAttribute -> data [ 'ShadowAttribute' ];
// 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
2013-08-20 10:17:37 +02:00
$this -> Attribute -> contain = 'Event' ;
2013-04-25 14:04:08 +02:00
$activeAttribute = $this -> Attribute -> findByUuid ( $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'uuid' ]);
// Send those away that shouldn't be able to see this
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-06-27 17:53:36 +02:00
if (( $activeAttribute [ 'Event' ][ 'orgc' ] != $this -> Auth -> user ( 'org' )) && ( $this -> Auth -> user ( 'org' ) != $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'org' ]) || ( ! $this -> userRole [ 'perm_modify' ] || ! $this -> userRole [ 'perm_publish' ])) {
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'Invalid attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
}
}
// Update the live attribute with the shadow data
$activeAttribute [ 'Attribute' ][ 'value1' ] = $shadow [ 'value1' ];
$activeAttribute [ 'Attribute' ][ 'value2' ] = $shadow [ 'value2' ];
$activeAttribute [ 'Attribute' ][ 'value' ] = $shadow [ 'value' ];
$activeAttribute [ 'Attribute' ][ 'type' ] = $shadow [ 'type' ];
$activeAttribute [ 'Attribute' ][ 'category' ] = $shadow [ 'category' ];
$activeAttribute [ 'Attribute' ][ 'to_ids' ] = $shadow [ 'to_ids' ];
$this -> Attribute -> save ( $activeAttribute [ 'Attribute' ]);
$this -> ShadowAttribute -> delete ( $id , $cascade = false );
$this -> loadModel ( 'Event' );
$this -> Event -> recursive = - 1 ;
2013-06-20 16:21:55 +02:00
// 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' ]);
$fieldList = array ( 'proposal_email_lock' , 'id' , 'info' , 'published' );
$event [ 'Event' ][ 'proposal_email_lock' ] = 0 ;
$event [ 'Event' ][ 'published' ] = 0 ;
$this -> Event -> save ( $event , array ( 'fieldList' => $fieldList ));
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'Proposed change accepted' , true ), 'default' , array ());
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $activeAttribute [ 'Attribute' ][ 'event_id' ]));
return ;
} 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
$this -> loadModel ( 'Event' );
$toDeleteId = $shadow [ 'id' ];
// Stuff that we won't use in its current form for the attribute
unset ( $shadow [ 'email' ], $shadow [ 'org' ], $shadow [ 'id' ], $shadow [ 'old_id' ]);
2013-06-20 16:21:55 +02:00
$this -> loadModel ( 'Event' );
2013-04-25 14:04:08 +02:00
$this -> Event -> recursive = - 1 ;
2013-06-20 16:21:55 +02:00
$event = $this -> Event -> read ( null , $shadow [ 'event_id' ]);
2013-04-25 14:04:08 +02:00
$attribute = $shadow ;
// set the distribution equal to that of the event
2013-06-20 16:21:55 +02:00
$attribute [ 'distribution' ] = $event [ 'Event' ][ 'distribution' ];
2013-04-25 14:04:08 +02:00
$this -> Attribute -> create ();
$this -> Attribute -> save ( $attribute );
if ( $this -> ShadowAttribute -> typeIsAttachment ( $shadow [ 'type' ])) {
$this -> _moveFile ( $toDeleteId , $this -> Attribute -> id , $shadow [ 'event_id' ]);
}
$this -> ShadowAttribute -> delete ( $toDeleteId , $cascade = false );
2013-06-20 16:21:55 +02:00
$fieldList = array ( 'proposal_email_lock' , 'id' , 'info' , 'published' );
$event [ 'Event' ][ 'proposal_email_lock' ] = 0 ;
$event [ 'Event' ][ 'published' ] = 0 ;
$this -> Event -> save ( $event , array ( 'fieldList' => $fieldList ));
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'Proposed attribute accepted' , true ), 'default' , array ());
2013-06-20 16:21:55 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $shadow [ 'event_id' ]));
2013-04-25 14:04:08 +02:00
}
}
// If we accept a proposed attachment, then the attachment itself needs to be moved from files/eventId/shadow/shadowId to files/eventId/attributeId
private function _moveFile ( $shadowId , $newId , $eventId ){
$pathOld = APP . " files " . DS . $eventId . DS . " shadow " . DS . $shadowId ;
$pathNew = APP . " files " . DS . $eventId . DS . $newId ;
if ( rename ( $pathOld , $pathNew )) {
return true ;
} else {
$this -> Session -> setFlash ( __ ( 'Moving of the file that this attachment references failed.' , true ), 'default' , array ());
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $eventId ));
}
}
/**
* discard method
*
* @ return void
*
*/
// 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 -> _isRest ()) {
throw new Exception ( 'This feature is limited to interactive users only.' );
}
$this -> ShadowAttribute -> id = $id ;
$this -> ShadowAttribute -> read ();
$eventId = $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'event_id' ];
$this -> loadModel ( 'Event' );
$this -> Event -> recursive = - 1 ;
$this -> Event -> id = $eventId ;
$this -> Event -> read ();
// Send those away that shouldn't be able to see this
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-06-27 17:53:36 +02:00
if (( $this -> Event -> data [ 'Event' ][ 'orgc' ] != $this -> Auth -> user ( 'org' )) && ( $this -> Auth -> user ( 'org' ) != $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'org' ]) && ( ! $this -> userRole [ 'perm_modify' ] || ! $this -> userRole [ 'perm_publish' ])) {
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'Invalid attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
}
}
$this -> ShadowAttribute -> delete ( $id , $cascade = false );
$this -> Session -> setFlash ( __ ( 'Proposed change discarded' , true ), 'default' , array ());
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $eventId ));
}
/**
* add method
*
* @ return void
*
* @ throws NotFoundException // TODO Exception
*/
public function add ( $eventId = null ) {
if ( $this -> request -> is ( 'post' )) {
// Give error if someone tried to submit a attribute with attachment or malware-sample type.
// 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 -> Session -> setFlash ( __ ( 'Attribute has not been added: attachments are added by "Add attachment" button' , true ), 'default' , array (), 'error' );
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
//
// multiple attributes in batch import
//
if (( 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' ]);
$fails = " " ; // will be used to keep a list of the lines that failed or succeeded
$successes = " " ;
// 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 -> 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' ] = $this -> Auth -> user ( 'org' );
// TODO loop-holes,
// there seems to be a loop-hole 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 ( $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' );
}
}
if ( $successes ) {
// list the ones that succeeded
$this -> Session -> setFlash ( __ ( 'The lines' . $successes . ' have been saved' , true ));
2013-06-20 16:21:55 +02:00
$this -> _setProposalLock ( $eventId , 1 );
2013-04-25 14:04:08 +02:00
}
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
} else {
if ( isset ( $this -> request -> data [ 'ShadowAttribute' ][ 'uuid' ])) { // TODO here we should start RESTful dialog
// check if the uuid already exists
}
//
// single attribute
//
// create the attribute
$this -> ShadowAttribute -> create ();
$savedId = $this -> ShadowAttribute -> getId ();
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$this -> request -> data [ 'ShadowAttribute' ][ 'org' ] = $this -> Auth -> user ( 'org' );
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
2013-06-20 16:21:55 +02:00
$this -> _setProposalLock ( $eventId , 1 );
2013-04-25 14:04:08 +02:00
// inform the user and redirect
2013-06-20 16:21:55 +02:00
$this -> Session -> setFlash ( __ ( 'The proposal has been saved' ));
2013-04-25 14:04:08 +02:00
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
} 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 [ 'ShadowAttribute' ][ 'event_id' ] = $eventId ;
}
// combobox for types
$types = array_keys ( $this -> ShadowAttribute -> typeDefinitions );
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobos for categories
$categories = $this -> ShadowAttribute -> validate [ 'category' ][ 'rule' ][ 1 ];
array_pop ( $categories );
$categories = $this -> _arrayToValuesIndexArray ( $categories );
$this -> set ( 'categories' , compact ( 'categories' ));
$this -> loadModel ( 'Event' );
$events = $this -> Event -> findById ( $eventId );
// combobox for distribution
$count = 0 ;
$this -> set ( 'attrDescriptions' , $this -> ShadowAttribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> ShadowAttribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> categoryDefinitions );
}
public function download ( $id = null ) {
$this -> ShadowAttribute -> id = $id ;
if ( ! $this -> ShadowAttribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid ShadowAttribute' ));
}
$this -> ShadowAttribute -> read ();
$path = APP . " files " . DS . $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'event_id' ] . DS . 'shadow' . DS ;
$file = $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'id' ];
$filename = '' ;
if ( 'attachment' == $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'type' ]) {
$filename = $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'value' ];
$fileExt = pathinfo ( $filename , PATHINFO_EXTENSION );
$filename = substr ( $filename , 0 , strlen ( $filename ) - strlen ( $fileExt ) - 1 );
} elseif ( 'malware-sample' == $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'type' ]) {
$filenameHash = explode ( '|' , $this -> ShadowAttribute -> data [ 'ShadowAttribute' ][ 'value' ]);
$filename = $filenameHash [ 0 ];
$filename = substr ( $filenameHash [ 0 ], strrpos ( $filenameHash [ 0 ], '\\' ));
$fileExt = " zip " ;
} else {
throw new NotFoundException ( __ ( 'ShadowAttribute 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-04-25 14:04:08 +02:00
}
/**
* add_attachment method
*
* @ return void
* @ throws InternalErrorException
*/
public function add_attachment ( $eventId = null ) {
if ( $this -> request -> is ( 'post' )) {
$this -> loadModel ( 'Event' );
// 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 [ '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 {
$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 [ 'ShadowAttribute' ][ 'event_id' ]));
}
$this -> Event -> id = $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ];
// save the file-info in the database
$this -> ShadowAttribute -> create ();
if ( $this -> request -> data [ 'ShadowAttribute' ][ 'malware' ]) {
$this -> request -> data [ 'ShadowAttribute' ][ 'type' ] = " malware-sample " ;
// Validate filename
2013-04-29 10:52:07 +02:00
if ( ! preg_match ( '@^[\w-,\s]+\.[A-Za-z0-9_]{2,4}$@' , $filename )) throw new Exception ( 'Filename not allowed' );
2013-04-25 14:04:08 +02:00
$this -> request -> data [ 'ShadowAttribute' ][ 'value' ] = $filename . '|' . $tmpfile -> md5 (); // TODO gives problems with bigger files
$this -> request -> data [ 'ShadowAttribute' ][ 'to_ids' ] = 1 ; // LATER let user choose to send this to IDS
} else {
$this -> request -> data [ 'ShadowAttribute' ][ 'type' ] = " attachment " ;
// Validate filename
2013-04-29 10:52:07 +02:00
if ( ! preg_match ( '@^[\w-,\s]+\.[A-Za-z0-9_]{2,4}$@' , $filename )) throw new Exception ( 'Filename not allowed' );
2013-04-25 14:04:08 +02:00
$this -> request -> data [ 'ShadowAttribute' ][ 'value' ] = $filename ;
$this -> request -> data [ 'ShadowAttribute' ][ 'to_ids' ] = 0 ;
}
$this -> request -> data [ 'ShadowAttribute' ][ 'uuid' ] = String :: uuid ();
$this -> request -> data [ 'ShadowAttribute' ][ 'batch_import' ] = 0 ;
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$this -> request -> data [ 'ShadowAttribute' ][ 'org' ] = $this -> Auth -> user ( 'org' );
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
2013-06-20 16:21:55 +02:00
$this -> _setProposalLock ( $eventId , 1 );
2013-04-25 14:04:08 +02:00
} else {
$this -> Session -> setFlash ( __ ( 'The ShadowAttribute could not be saved. Did you already upload this file?' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
// no errors in file upload, entry already in db, now move the file where needed and zip it if required.
// no sanitization is required on the filename, path or type as we save
// create directory structure
if ( PHP_OS == 'WINNT' ) {
$rootDir = APP . " files " . DS . $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] . DS . " shadow " ;
} else {
$rootDir = APP . DS . " files " . DS . $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] . DS . " shadow " ;
}
$dir = new Folder ( $rootDir , true );
// move the file to the correct location
$destpath = $rootDir . DS . $this -> ShadowAttribute -> id ; // id of the new ShadowAttribute in the database
$file = new File ( $destpath );
$zipfile = new File ( $destpath . '.zip' );
$fileInZip = new File ( $rootDir . DS . $filename ); // FIXME do sanitization of the filename
if ( $file -> exists () || $zipfile -> exists () || $fileInZip -> exists ()) {
// this should never happen as the ShadowAttribute id should be unique
$this -> Session -> setFlash ( __ ( 'Attachment with this name already exist in this event.' , true ), 'default' , array (), 'error' );
// remove the entry from the database
$this -> ShadowAttribute -> delete ();
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
if ( ! move_uploaded_file ( $tmpfile -> path , $file -> path )) {
$this -> Session -> setFlash ( __ ( 'Problem with uploading attachment. Cannot move it to its final location.' , true ), 'default' , array (), 'error' );
// remove the entry from the database
$this -> ShadowAttribute -> delete ();
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
}
// zip and password protect the malware files
if ( $this -> request -> data [ 'ShadowAttribute' ][ 'malware' ]) {
// TODO check if CakePHP has no easy/safe wrapper to execute commands
$execRetval = '' ;
$execOutput = array ();
rename ( $file -> path , $fileInZip -> path ); // TODO check if no workaround exists for the current filtering mechanisms
if ( PHP_OS == 'WINNT' ) {
exec ( " zip -j -P infected " . $zipfile -> path . ' "' . $fileInZip -> path . '"' , $execOutput , $execRetval );
} else {
exec ( " zip -j -P infected " . $zipfile -> path . ' "' . addslashes ( $fileInZip -> path ) . '"' , $execOutput , $execRetval );
}
if ( $execRetval != 0 ) { // not EXIT_SUCCESS
$this -> Session -> setFlash ( __ ( 'Problem with zipping the attachment. Please report to administrator. ' . $execOutput , true ), 'default' , array (), 'error' );
// remove the entry from the database
$this -> ShadowAttribute -> delete ();
$fileInZip -> delete ();
$file -> delete ();
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
};
$fileInZip -> delete (); // delete the original not-zipped-file
rename ( $zipfile -> path , $file -> path ); // rename the .zip to .nothing
}
// everything is done, now redirect to event view
$this -> Session -> setFlash ( __ ( 'The attachment has been uploaded' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ]));
} else {
// set the event_id in the form
$this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] = $eventId ;
$this -> loadModel ( 'Event' );
$events = $this -> Event -> findById ( $eventId );
}
// combobox for categories
$categories = $this -> ShadowAttribute -> validate [ 'category' ][ 'rule' ][ 1 ];
// 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 ;
continue ;
}
}
}
};
$categories = $this -> _arrayToValuesIndexArray ( $selectedCategories );
$this -> set ( 'categories' , $categories );
$this -> set ( 'attrDescriptions' , $this -> ShadowAttribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> ShadowAttribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> categoryDefinitions );
$this -> set ( 'zippedDefinitions' , $this -> ShadowAttribute -> zippedDefinitions );
$this -> set ( 'uploadDefinitions' , $this -> ShadowAttribute -> uploadDefinitions );
}
/**
* edit method
*
* @ param string $id
* @ return void
* @ throws NotFoundException
*/
// Propose an edit to an attribute
public function edit ( $id = null ) {
$this -> loadModel ( 'Attribute' );
$this -> Attribute -> id = $id ;
if ( ! $this -> Attribute -> exists ()) {
throw new NotFoundException ( __ ( 'Invalid Attribute' ));
}
$this -> Attribute -> read ();
if ( $this -> _isRest ()) {
throw new Exception ( 'Proposing a change to an attribute can only be done via the interactive interface.' );
}
$uuid = $this -> Attribute -> data [ 'Attribute' ][ 'uuid' ];
2013-06-20 16:21:55 +02:00
if ( ! $this -> _isSiteAdmin ()) {
2013-06-11 13:51:11 +02:00
if (( $this -> Attribute -> data [ 'Attribute' ][ 'distribution' ] == 0 ) || ( $this -> Attribute -> data [ 'Event' ][ 'org' ] == $this -> Auth -> user ( 'org' ))) {
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'Invalid Attribute.' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'index' ));
}
}
// Check if the attribute is an attachment, if yes, block the type and the value fields from being edited.
$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 );
$attachment = true ;
} else {
$this -> set ( 'attachment' , false );
$attachment = false ;
}
if ( $this -> request -> is ( 'post' ) || $this -> request -> is ( 'put' )) {
$existingAttribute = $this -> Attribute -> findByUuid ( $uuid );
$this -> request -> data [ 'ShadowAttribute' ][ 'old_id' ] = $existingAttribute [ 'Attribute' ][ 'id' ];
$this -> request -> data [ 'ShadowAttribute' ][ 'uuid' ] = $existingAttribute [ 'Attribute' ][ 'uuid' ];
$this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ] = $existingAttribute [ 'Attribute' ][ 'event_id' ];
if ( $attachment ) $this -> request -> data [ 'ShadowAttribute' ][ 'value' ] = $existingAttribute [ 'Attribute' ][ 'value' ];
if ( $attachment ) $this -> request -> data [ 'ShadowAttribute' ][ 'type' ] = $existingAttribute [ 'Attribute' ][ 'type' ];
$this -> request -> data [ 'ShadowAttribute' ][ 'org' ] = $this -> Auth -> user ( 'org' );
$this -> request -> data [ 'ShadowAttribute' ][ 'email' ] = $this -> Auth -> user ( 'email' );
$fieldList = array ( 'category' , 'type' , 'value1' , 'value2' , 'to_ids' , 'value' , 'org' );
if ( $this -> ShadowAttribute -> save ( $this -> request -> data )) {
2013-06-20 16:21:55 +02:00
$this -> _setProposalLock ( $this -> request -> data [ 'ShadowAttribute' ][ 'event_id' ], 1 );
2013-04-25 14:04:08 +02:00
$this -> Session -> setFlash ( __ ( 'The proposed Attribute has been saved' ));
$this -> redirect ( array ( 'controller' => 'events' , 'action' => 'view' , $eventId ));
} else {
$this -> Session -> setFlash ( __ ( 'The ShadowAttribute could not be saved. Please, try again.' ));
}
} else {
// Read the attribute that we're about to edit
$this -> ShadowAttribute -> create ();
$this -> Attribute -> recursive = - 1 ;
$request = $this -> Attribute -> read ( null , $id );
$request [ 'ShadowAttribute' ] = $request [ 'Attribute' ];
$this -> request -> data = $request ;
unset ( $this -> request -> data [ 'ShadowAttribute' ][ 'id' ]);
}
// combobox for types
$types = array_keys ( $this -> ShadowAttribute -> typeDefinitions );
$types = $this -> _arrayToValuesIndexArray ( $types );
$this -> set ( 'types' , $types );
// combobox for categories
$categories = $this -> ShadowAttribute -> validate [ 'category' ][ 'rule' ][ 1 ];
array_pop ( $categories ); // remove that last empty/space option
$categories = $this -> _arrayToValuesIndexArray ( $categories );
$this -> set ( 'categories' , $categories );
$this -> set ( 'attrDescriptions' , $this -> ShadowAttribute -> fieldDescriptions );
$this -> set ( 'typeDefinitions' , $this -> ShadowAttribute -> typeDefinitions );
$this -> set ( 'categoryDefinitions' , $this -> ShadowAttribute -> categoryDefinitions );
}
2013-06-20 16:21:55 +02:00
private function _setProposalLock ( $id , $setting ) {
// This method is used to change the proposalLock to the opposite of the passed argument setting if the current setting doesn't match and save the event
$this -> loadModel ( 'Event' );
$this -> Event -> recursive = - 1 ;
$event = $this -> Event -> read ( null , $id );
if ( $setting == 1 ) {
if ( $event [ 'Event' ][ 'proposal_email_lock' ] == 0 ) {
$fieldList = array ( 'proposal_email_lock' , 'id' , 'info' );
$event [ 'Event' ][ 'proposal_email_lock' ] = 1 ;
$this -> Event -> save ( $event , array ( 'fieldList' => $fieldList ));
$this -> __sendProposalAlertEmail ( $id );
}
} else {
if ( $event [ 'Event' ][ 'proposal_email_lock' ] == 1 ) {
$fieldList = array ( 'proposal_email_lock' , 'id' , 'info' );
$event [ 'Event' ][ 'proposal_email_lock' ] = 0 ;
$this -> Event -> save ( $event , array ( 'fieldList' => $fieldList ));
}
}
}
private function __sendProposalAlertEmail ( $id ) {
$this -> loadModel ( 'Event' );
$this -> Event -> recursive = - 1 ;
$event = $this -> Event -> read ( null , $id );
$this -> loadModel ( 'User' );
$this -> User -> recursive = - 1 ;
$orgMembers = array ();
$temp = $this -> User -> findAllByOrg ( $event [ 'Event' ][ 'orgc' ], array ( 'email' , 'gpgkey' , 'contactalert' , 'id' ));
foreach ( $temp as $tempElement ) {
if ( $tempElement [ 'User' ][ 'contactalert' ] || $tempElement [ 'User' ][ 'id' ] == $event [ 'Event' ][ 'user_id' ]) {
array_push ( $orgMembers , $tempElement );
}
}
$body = " " ;
$body .= " Hello, \n " ;
$body .= " \n " ;
$body .= " A user of another organisation has proposed a change to an event created by you or your organisations. \n " ;
$body .= " \n " ;
$body .= " To view the event in question, follow this link: " ;
$body .= ' ' . Configure :: read ( 'CyDefSIG.baseurl' ) . '/events/view/' . $id . " \n " ;
$body .= " \n " ;
$body .= " You can reach the user at " . $this -> Auth -> user ( 'email' );
$body .= " \n " ;
// sign the body
require_once 'Crypt/GPG.php' ;
$gpg = new Crypt_GPG ( array ( 'homedir' => Configure :: read ( 'GnuPG.homedir' ))); // , 'debug' => true
$gpg -> addSignKey ( Configure :: read ( 'GnuPG.email' ), Configure :: read ( 'GnuPG.password' ));
$bodySigned = $gpg -> sign ( $body , Crypt_GPG :: SIGN_MODE_CLEAR );
// Add the GPG key of the user as attachment
// LATER sign the attached GPG key
if ( null != ( $this -> Auth -> user ( 'gpgkey' ))) {
// save the gpg key to a temporary file
$tmpfname = tempnam ( TMP , " GPGkey " );
$handle = fopen ( $tmpfname , " w " );
fwrite ( $handle , $this -> Auth -> user ( 'gpgkey' ));
fclose ( $handle );
// attach it
$this -> Email -> attachments = array (
'gpgkey.asc' => $tmpfname
);
}
foreach ( $orgMembers as & $reporter ) {
if ( ! empty ( $reporter [ 'User' ][ 'gpgkey' ])) {
// import the key of the user into the keyring
// this isn't really necessary, but it gives it the fingerprint necessary for the next step
$keyImportOutput = $gpg -> importKey ( $reporter [ 'User' ][ 'gpgkey' ]);
// say what key should be used to encrypt
try {
$gpg = new Crypt_GPG ( array ( 'homedir' => Configure :: read ( 'GnuPG.homedir' )));
$gpg -> addEncryptKey ( $keyImportOutput [ 'fingerprint' ]); // use the key that was given in the import
$bodyEncSig = $gpg -> encrypt ( $bodySigned , true );
} catch ( Exception $e ){
// catch errors like expired PGP keys
$this -> log ( $e -> getMessage ());
// no need to return here, as we want to send out mails to the other users if GPG encryption fails for a single user
}
} else {
$bodyEncSig = $bodySigned ;
// FIXME should I allow sending unencrypted "contact" mails to people if they didn't import they GPG key?
}
// prepare the email
$this -> Email -> from = Configure :: read ( 'CyDefSIG.email' );
$this -> Email -> to = $reporter [ 'User' ][ 'email' ];
$this -> Email -> subject = " [ " . Configure :: read ( 'CyDefSIG.name' ) . " ] Proposal to event # " . $id ;
$this -> Email -> delivery = 'debug' ; // do not really send out mails, only display it on the screen
$this -> Email -> template = 'body' ;
$this -> Email -> sendAs = 'text' ; // both text or html
$this -> set ( 'body' , $bodyEncSig );
// Add the GPG key of the user as attachment
// LATER sign the attached GPG key
if ( null != ( $this -> Auth -> user ( 'gpgkey' ))) {
// attach the gpg key
$this -> Email -> attachments = array (
'gpgkey.asc' => $tmpfname
);
}
// send it
$result = $this -> Email -> send ();
// If you wish to send multiple emails using a loop, you'll need
// to reset the email fields using the reset method of the Email component.
$this -> Email -> reset ();
}
}
2013-04-25 14:04:08 +02:00
}