2013-04-25 14:04:08 +02:00
< ? php
App :: uses ( 'AppModel' , 'Model' );
App :: uses ( 'Folder' , 'Utility' );
App :: uses ( 'File' , 'Utility' );
class ShadowAttribute extends AppModel {
public $combinedKeys = array ( 'event_id' , 'category' , 'type' );
public $name = 'ShadowAttribute' ; // TODO general
public $actsAs = array (
2014-01-28 16:27:58 +01:00
'SysLogLogable.SysLogLogable' => array ( // TODO Audit, logable
'userModel' => 'User' ,
'userKey' => 'user_id' ,
'change' => 'full' ),
2013-04-25 14:04:08 +02:00
'Trim' ,
'Containable' ,
2013-04-25 15:37:49 +02:00
'Regexp' => array ( 'fields' => array ( 'value' , 'value2' )),
2013-04-25 14:04:08 +02:00
);
2013-09-03 15:32:12 +02:00
public $belongsTo = array (
'Event' => array (
'className' => 'Event' ,
'foreignKey' => 'event_id' ,
'conditions' => '' ,
'fields' => '' ,
'order' => '' ,
'counterCache' => true
2015-09-21 14:55:40 +02:00
),
'Org' => array (
'className' => 'Organisation' ,
'foreignKey' => 'org_id'
),
'EventOrg' => array (
'className' => 'Organisation' ,
'foreignKey' => 'event_org_id'
),
2013-09-03 15:32:12 +02:00
);
2013-04-25 14:04:08 +02:00
public $displayField = 'value' ;
public $virtualFields = array (
2016-07-11 20:24:03 +02:00
'value' => " CASE WHEN ShadowAttribute.value2 = '' THEN ShadowAttribute.value1 ELSE CONCAT(ShadowAttribute.value1, '|', ShadowAttribute.value2) END " ,
2013-04-25 14:04:08 +02:00
); // TODO hardcoded
2016-08-25 11:38:37 +02:00
// explanations of certain fields to be used in various views
2013-04-25 14:04:08 +02:00
public $fieldDescriptions = array (
'signature' => array ( 'desc' => 'Is this attribute eligible to automatically create an IDS signature (network IDS or host IDS) out of it ?' ),
//'private' => array('desc' => 'Prevents upload of this single Attribute to other CyDefSIG servers', 'formdesc' => 'Prevents upload of <em>this single Attribute</em> to other CyDefSIG servers.<br/>Used only when the Event is NOT set as Private')
);
// if these then a category my have upload to be zipped
public $zippedDefinitions = array (
'malware-sample'
);
// if these then a category my have upload
public $uploadDefinitions = array (
'attachment'
);
// definitions of categories
2015-07-06 18:19:51 +02:00
public $categoryDefinitions ;
2013-04-25 14:04:08 +02:00
public $order = array ( " ShadowAttribute.event_id " => " DESC " , " ShadowAttribute.type " => " ASC " );
public $validate = array (
'event_id' => array (
'numeric' => array (
2017-04-13 21:51:20 +02:00
'rule' => array ( 'numeric' )
)
),
'org_id' => array (
'numeric' => array (
'rule' => array ( 'numeric' )
)
),
'event_org_id' => array (
'numeric' => array (
'rule' => array ( 'numeric' )
)
2013-04-25 14:04:08 +02:00
),
'type' => array (
// currently when adding a new attribute type we need to change it in both places
'rule' => array ( 'validateTypeValue' ),
'message' => 'Options depend on the selected category.' ,
//'allowEmpty' => false,
'required' => true ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
// this could be initialized from categoryDefinitions but dunno how at the moment
'category' => array (
2015-10-16 23:49:04 +02:00
'validCategory' => array (
'rule' => array ( 'validCategory' ),
'message' => 'Options : Payload delivery, Antivirus detection, Payload installation, Files dropped ...'
),
2013-04-25 14:04:08 +02:00
),
'value' => array (
2018-04-09 13:58:24 +02:00
'stringNotEmpty' => array (
'rule' => array ( 'stringNotEmpty' ),
2013-04-25 14:04:08 +02:00
),
'userdefined' => array (
'rule' => array ( 'validateAttributeValue' ),
2016-05-20 16:46:06 +02:00
'message' => 'Value not in the right type/format. Please double check the value or select type "other".' ,
2013-04-25 14:04:08 +02:00
),
),
'to_ids' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
'required' => false ,
),
),
'uuid' => array (
'uuid' => array (
2017-06-12 22:39:02 +02:00
'rule' => array ( 'custom' , '/^[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}$/' ),
'message' => 'Please provide a valid UUID'
2013-04-25 14:04:08 +02:00
),
),
2015-10-16 23:49:04 +02:00
'proposal_to_delete' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
),
),
2013-04-25 14:04:08 +02:00
);
public function __construct ( $id = false , $table = null , $ds = null ) {
parent :: __construct ( $id , $table , $ds );
2013-04-25 15:37:49 +02:00
$this -> virtualFields = Set :: merge ( $this -> virtualFields , array (
//'distribution' => 'IF (Attribute.private=true, "Your organization only", IF (Attribute.cluster=true, "This Community-only", "All communities"))',
//'distribution' => 'IF (ShadowAttribute.private=true AND ShadowAttribute.cluster=false, "Your organization only", IF (ShadowAttribute.private=true AND ShadowAttribute.cluster=true, "This server-only", IF (ShadowAttribute.private=false AND ShadowAttribute.cluster=true, "This Community-only", IF (ShadowAttribute.communitie=true, "Connected communities" , "All communities"))))',
));
$this -> fieldDescriptions = Set :: merge ( $this -> fieldDescriptions , array (
//'distribution' => array('desc' => 'This fields indicates the intended distribution of the attribute (same as when adding an event, see Add Event)'),
));
2015-07-06 18:19:51 +02:00
$this -> categoryDefinitions = $this -> Event -> Attribute -> categoryDefinitions ;
$this -> typeDefinitions = $this -> Event -> Attribute -> typeDefinitions ;
2013-04-25 14:04:08 +02:00
}
2016-05-20 19:00:03 +02:00
// The Associations below have been created with all possible keys, those that are not needed can be removed
2016-06-04 01:08:16 +02:00
2013-04-25 14:04:08 +02:00
public function beforeSave ( $options = array ()) {
// explode value of composite type in value1 and value2
// or copy value to value1 if not composite type
if ( ! empty ( $this -> data [ 'ShadowAttribute' ][ 'type' ])) {
$compositeTypes = $this -> getCompositeTypes ();
// explode composite types in value1 and value2
$pieces = explode ( '|' , $this -> data [ 'ShadowAttribute' ][ 'value' ]);
if ( in_array ( $this -> data [ 'ShadowAttribute' ][ 'type' ], $compositeTypes )) {
if ( 2 != count ( $pieces )) {
throw new InternalErrorException ( 'Composite type, but value not explodable' );
}
$this -> data [ 'ShadowAttribute' ][ 'value1' ] = $pieces [ 0 ];
$this -> data [ 'ShadowAttribute' ][ 'value2' ] = $pieces [ 1 ];
} else {
$total = implode ( '|' , $pieces );
$this -> data [ 'ShadowAttribute' ][ 'value1' ] = $total ;
$this -> data [ 'ShadowAttribute' ][ 'value2' ] = '' ;
}
}
2016-08-17 03:15:57 +02:00
if ( ! isset ( $this -> data [ 'ShadowAttribute' ][ 'deleted' ])) $this -> data [ 'ShadowAttribute' ][ 'deleted' ] = 0 ;
2016-03-09 14:34:35 +01:00
if ( $this -> data [ 'ShadowAttribute' ][ 'deleted' ]) $this -> __beforeDeleteCorrelation ( $this -> data [ 'ShadowAttribute' ]);
2013-04-25 14:04:08 +02:00
return true ;
}
2016-09-04 23:31:24 +02:00
private function __beforeDeleteCorrelation ( $sa ) {
if ( isset ( $sa [ 'ShadowAttribute' ])) $sa = $sa [ 'ShadowAttribute' ];
2016-02-17 14:43:33 +01:00
$this -> ShadowAttributeCorrelation = ClassRegistry :: init ( 'ShadowAttributeCorrelation' );
2016-09-04 23:31:24 +02:00
$this -> ShadowAttributeCorrelation -> deleteAll ( array ( 'ShadowAttributeCorrelation.1_shadow_attribute_id' => $sa [ 'id' ]));
2016-02-17 14:43:33 +01:00
}
2016-06-04 01:08:16 +02:00
2016-09-04 23:31:24 +02:00
private function __afterSaveCorrelation ( $sa ) {
if ( isset ( $sa [ 'ShadowAttribute' ])) $sa = $sa [ 'ShadowAttribute' ];
if ( in_array ( $sa [ 'type' ], $this -> Event -> Attribute -> nonCorrelatingTypes )) return ;
2016-02-17 14:43:33 +01:00
$this -> ShadowAttributeCorrelation = ClassRegistry :: init ( 'ShadowAttributeCorrelation' );
$shadow_attribute_correlations = array ();
$fields = array ( 'value1' , 'value2' );
2016-09-04 23:31:24 +02:00
$correlatingValues = array ( $sa [ 'value1' ]);
if ( ! empty ( $sa [ 'value2' ])) $correlatingValues [] = $sa [ 'value2' ];
2016-02-17 14:43:33 +01:00
foreach ( $correlatingValues as $k => $cV ) {
$correlatingAttributes [ $k ] = $this -> Event -> Attribute -> find ( 'all' , array (
'conditions' => array (
'AND' => array (
'OR' => array (
'Attribute.value1' => $cV ,
'Attribute.value2' => $cV
),
'Attribute.type !=' => $this -> Event -> Attribute -> nonCorrelatingTypes ,
2016-10-21 13:55:10 +02:00
'Attribute.deleted' => 0 ,
'Attribute.event_id !=' => $sa [ 'event_id' ]
2016-02-17 14:43:33 +01:00
),
),
'recursive => -1' ,
'fields' => array ( 'Attribute.event_id' , 'Attribute.id' , 'Attribute.distribution' , 'Attribute.sharing_group_id' ),
'contain' => array ( 'Event' => array ( 'fields' => array ( 'Event.id' , 'Event.date' , 'Event.info' , 'Event.org_id' , 'Event.distribution' , 'Event.sharing_group_id' ))),
'order' => array (),
));
2016-07-07 15:38:27 +02:00
foreach ( $correlatingAttributes as $key => $cA ) {
2016-02-17 14:43:33 +01:00
foreach ( $cA as $corr ) {
$shadow_attribute_correlations [] = array (
2016-07-07 15:38:27 +02:00
'value' => $correlatingValues [ $key ],
2016-09-04 23:31:24 +02:00
'1_event_id' => $sa [ 'event_id' ],
'1_shadow_attribute_id' => $sa [ 'id' ],
2016-02-17 14:43:33 +01:00
'event_id' => $corr [ 'Attribute' ][ 'event_id' ],
'attribute_id' => $corr [ 'Attribute' ][ 'id' ],
'org_id' => $corr [ 'Event' ][ 'org_id' ],
'distribution' => $corr [ 'Event' ][ 'distribution' ],
'a_distribution' => $corr [ 'Attribute' ][ 'distribution' ],
'sharing_group_id' => $corr [ 'Event' ][ 'sharing_group_id' ],
'a_sharing_group_id' => $corr [ 'Attribute' ][ 'sharing_group_id' ],
'date' => $corr [ 'Event' ][ 'date' ],
'info' => $corr [ 'Event' ][ 'info' ],
);
}
}
}
if ( ! empty ( $shadow_attribute_correlations )) $this -> ShadowAttributeCorrelation -> saveMany ( $shadow_attribute_correlations );
}
2016-06-04 01:08:16 +02:00
2013-11-06 10:35:51 +01:00
public function afterSave ( $created , $options = array ()) {
2013-04-25 14:04:08 +02:00
$result = true ;
// if the 'data' field is set on the $this->data then save the data to the correct file
2015-11-27 09:16:17 +01:00
if ( isset ( $this -> data [ 'ShadowAttribute' ][ 'deleted' ]) && $this -> data [ 'ShadowAttribute' ][ 'deleted' ]) {
$sa = $this -> find ( 'first' , array ( 'conditions' => array ( 'ShadowAttribute.id' => $this -> data [ 'ShadowAttribute' ][ 'id' ]), 'recursive' => - 1 , 'fields' => array ( 'ShadowAttribute.id' , 'ShadowAttribute.event_id' , 'ShadowAttribute.type' )));
if ( $this -> typeIsAttachment ( $sa [ 'ShadowAttribute' ][ 'type' ])) {
// only delete the file if it exists
2017-07-07 17:29:13 +02:00
$attachments_dir = Configure :: read ( 'MISP.attachments_dir' );
if ( empty ( $attachments_dir )) {
$my_server = ClassRegistry :: init ( 'Server' );
2017-07-10 12:42:23 +02:00
$attachments_dir = $my_server -> getDefaultAttachments_dir ();
2017-07-07 17:29:13 +02:00
}
$filepath = $attachments_dir . DS . 'shadow' . DS . $sa [ 'ShadowAttribute' ][ 'event_id' ] . DS . $sa [ 'ShadowAttribute' ][ 'id' ];
2016-05-20 16:57:34 +02:00
$file = new File ( $filepath );
2015-11-27 09:16:17 +01:00
if ( $file -> exists ()) {
if ( ! $file -> delete ()) {
throw new InternalErrorException ( 'Delete of file attachment failed. Please report to administrator.' );
}
}
}
} else {
if ( isset ( $this -> data [ 'ShadowAttribute' ][ 'type' ]) && $this -> typeIsAttachment ( $this -> data [ 'ShadowAttribute' ][ 'type' ]) && ! empty ( $this -> data [ 'ShadowAttribute' ][ 'data' ])) {
$result = $result && $this -> saveBase64EncodedAttachment ( $this -> data [ 'ShadowAttribute' ]);
}
2013-04-25 14:04:08 +02:00
}
2016-02-17 14:43:33 +01:00
if (( isset ( $this -> data [ 'ShadowAttribute' ][ 'deleted' ]) && $this -> data [ 'ShadowAttribute' ][ 'deleted' ]) || ( isset ( $this -> data [ 'ShadowAttribute' ][ 'proposal_to_delete' ]) && $this -> data [ 'ShadowAttribute' ][ 'proposal_to_delete' ])) {
// this is a deletion
// Could be a proposal to delete or flagging a proposal that it was discarded / accepted - either way, we don't want to correlate here for now
} else {
$this -> __afterSaveCorrelation ( $this -> data [ 'ShadowAttribute' ]);
}
2013-04-25 14:04:08 +02:00
return $result ;
}
public function beforeDelete ( $cascade = true ) {
// delete attachments from the disk
$this -> read (); // first read the attribute from the db
if ( $this -> typeIsAttachment ( $this -> data [ 'ShadowAttribute' ][ 'type' ])) {
// only delete the file if it exists
2017-07-07 17:29:13 +02:00
$attachments_dir = Configure :: read ( 'MISP.attachments_dir' );
if ( empty ( $attachments_dir )) {
$my_server = ClassRegistry :: init ( 'Server' );
2017-07-10 12:42:23 +02:00
$attachments_dir = $my_server -> getDefaultAttachments_dir ();
2017-07-07 17:29:13 +02:00
}
$filepath = $attachments_dir . DS . 'shadow' . DS . $this -> data [ 'ShadowAttribute' ][ 'event_id' ] . DS . $this -> data [ 'ShadowAttribute' ][ 'id' ];
2016-05-20 16:57:34 +02:00
$file = new File ( $filepath );
2013-04-25 14:04:08 +02:00
if ( $file -> exists ()) {
if ( ! $file -> delete ()) {
throw new InternalErrorException ( 'Delete of file attachment failed. Please report to administrator.' );
}
}
}
}
public function beforeValidate ( $options = array ()) {
parent :: beforeValidate ();
// remove leading and trailing blanks
//$this->trimStringFields(); // TODO
2016-12-09 09:26:58 +01:00
if ( isset ( $this -> data [ 'ShadowAttribute' ][ 'value' ])) {
$this -> data [ 'ShadowAttribute' ][ 'value' ] = trim ( $this -> data [ 'ShadowAttribute' ][ 'value' ]);
}
if ( ! isset ( $this -> data [ 'ShadowAttribute' ][ 'comment' ])) {
$this -> data [ 'ShadowAttribute' ][ 'comment' ] = '' ;
}
2013-04-25 14:04:08 +02:00
if ( ! isset ( $this -> data [ 'ShadowAttribute' ][ 'type' ])) {
return false ;
}
2016-06-04 01:08:16 +02:00
2014-08-14 11:33:33 +02:00
if ( empty ( $this -> data [ 'ShadowAttribute' ][ 'timestamp' ])) {
$date = new DateTime ();
$this -> data [ 'ShadowAttribute' ][ 'timestamp' ] = $date -> getTimestamp ();
}
2017-04-13 21:51:20 +02:00
2017-03-06 09:57:32 +01:00
if ( ! isset ( $this -> data [ 'ShadowAttribute' ][ 'proposal_to_delete' ])) $this -> data [ 'ShadowAttribute' ][ 'proposal_to_delete' ] = 0 ;
2013-04-25 14:04:08 +02:00
2015-07-06 18:19:51 +02:00
// make some last changes to the inserted value
$this -> data [ 'ShadowAttribute' ][ 'value' ] = $this -> Event -> Attribute -> modifyBeforeValidation ( $this -> data [ 'ShadowAttribute' ][ 'type' ], $this -> data [ 'ShadowAttribute' ][ 'value' ]);
2013-04-25 14:04:08 +02:00
// generate UUID if it doesn't exist
if ( empty ( $this -> data [ 'ShadowAttribute' ][ 'uuid' ])) {
2016-07-11 00:59:47 +02:00
$this -> data [ 'ShadowAttribute' ][ 'uuid' ] = CakeText :: uuid ();
2013-04-25 14:04:08 +02:00
}
// always return true, otherwise the object cannot be saved
return true ;
}
public function validateTypeValue ( $fields ) {
$category = $this -> data [ 'ShadowAttribute' ][ 'category' ];
if ( isset ( $this -> categoryDefinitions [ $category ][ 'types' ])) {
return in_array ( $fields [ 'type' ], $this -> categoryDefinitions [ $category ][ 'types' ]);
}
return false ;
}
2016-06-04 01:08:16 +02:00
2015-10-16 23:49:04 +02:00
public function validCategory ( $fields ) {
return $this -> Event -> Attribute -> validCategory ( $fields );
}
2013-04-25 14:04:08 +02:00
public function validateAttributeValue ( $fields ) {
2014-08-13 16:13:38 +02:00
$value = $fields [ 'value' ];
return $this -> Event -> Attribute -> runValidation ( $value , $this -> data [ 'ShadowAttribute' ][ 'type' ]);
2013-04-25 14:04:08 +02:00
}
public function getCompositeTypes () {
// build the list of composite Attribute.type dynamically by checking if type contains a |
// default composite types
$compositeTypes = array ( 'malware-sample' ); // TODO hardcoded composite
// dynamically generated list
foreach ( array_keys ( $this -> typeDefinitions ) as $type ) {
$pieces = explode ( '|' , $type );
if ( 2 == count ( $pieces )) {
$compositeTypes [] = $type ;
}
}
return $compositeTypes ;
}
public function typeIsMalware ( $type ) {
if ( in_array ( $type , $this -> zippedDefinitions )) {
return true ;
} else {
return false ;
}
}
public function typeIsAttachment ( $type ) {
if (( in_array ( $type , $this -> zippedDefinitions )) || ( in_array ( $type , $this -> uploadDefinitions ))) {
return true ;
} else {
return false ;
}
}
public function base64EncodeAttachment ( $attribute ) {
2017-07-07 17:29:13 +02:00
$attachments_dir = Configure :: read ( 'MISP.attachments_dir' );
if ( empty ( $attachments_dir )) {
$my_server = ClassRegistry :: init ( 'Server' );
2017-07-10 12:42:23 +02:00
$attachments_dir = $my_server -> getDefaultAttachments_dir ();
2017-07-07 17:29:13 +02:00
}
$filepath = $attachments_dir . DS . 'shadow' . DS . $attribute [ 'event_id' ] . DS . $attribute [ 'id' ];
2013-04-25 14:04:08 +02:00
$file = new File ( $filepath );
if ( ! $file -> exists ()) {
return '' ;
}
$content = $file -> read ();
return base64_encode ( $content );
}
public function saveBase64EncodedAttachment ( $attribute ) {
2017-07-07 17:29:13 +02:00
$attachments_dir = Configure :: read ( 'MISP.attachments_dir' );
if ( empty ( $attachments_dir )) {
$my_server = ClassRegistry :: init ( 'Server' );
2017-07-10 12:42:23 +02:00
$attachments_dir = $my_server -> getDefaultAttachments_dir ();
2017-07-07 17:29:13 +02:00
}
$rootDir = $attachments_dir . DS . 'shadow' . DS . $attribute [ 'event_id' ];
2013-04-25 14:04:08 +02:00
$dir = new Folder ( $rootDir , true ); // create directory structure
$destpath = $rootDir . DS . $attribute [ 'id' ];
2016-05-31 18:00:15 +02:00
$file = new File ( $destpath , true ); // create the file
2013-04-25 14:04:08 +02:00
$decodedData = base64_decode ( $attribute [ 'data' ]); // decode
if ( $file -> write ( $decodedData )) { // save the data
return true ;
} else {
// error
return false ;
}
}
public function checkComposites () {
$compositeTypes = $this -> getCompositeTypes ();
$fails = array ();
$attributes = $this -> find ( 'all' , array ( 'recursive' => 0 ));
foreach ( $attributes as $attribute ) {
if (( in_array ( $attribute [ 'ShadowAttribute' ][ 'type' ], $compositeTypes )) && ( ! strlen ( $attribute [ 'ShadowAttribute' ][ 'value1' ]) || ! strlen ( $attribute [ 'ShadowAttribute' ][ 'value2' ]))) {
$fails [] = $attribute [ 'ShadowAttribute' ][ 'event_id' ] . ':' . $attribute [ 'ShadowAttribute' ][ 'id' ];
}
}
return $fails ;
}
2016-06-04 01:08:16 +02:00
2014-08-11 15:11:57 +02:00
public function setDeleted ( $id ) {
2014-10-15 15:39:28 +02:00
$this -> Behaviors -> detach ( 'SysLogLogable.SysLogLogable' );
2016-02-17 14:43:33 +01:00
$sa = $this -> find ( 'first' , array ( 'conditions' => array ( 'ShadowAttribute.id' => $id ), 'recusive' => - 1 ));
if ( empty ( $sa )) return false ;
2014-08-14 11:33:33 +02:00
$date = new DateTime ();
2016-02-17 14:43:33 +01:00
$sa [ 'ShadowAttribute' ][ 'deleted' ] = 1 ;
$sa [ 'ShadowAttribute' ][ 'timestamp' ] = $date -> getTimestamp ();
$this -> save ( $sa );
2014-10-15 15:39:28 +02:00
return true ;
2014-08-14 11:33:33 +02:00
}
2016-06-04 01:08:16 +02:00
2014-08-14 11:33:33 +02:00
public function findOldProposal ( $sa ) {
$oldsa = $this -> find ( 'first' , array (
'conditions' => array (
'event_uuid' => $sa [ 'event_uuid' ],
'value' => $sa [ 'value' ],
'type' => $sa [ 'type' ],
'category' => $sa [ 'category' ],
'to_ids' => $sa [ 'to_ids' ],
2016-01-14 02:46:10 +01:00
'comment' => $sa [ 'comment' ]
2014-08-14 11:33:33 +02:00
),
));
if ( empty ( $oldsa )) return false ;
else return $oldsa [ 'ShadowAttribute' ];
2014-08-11 15:11:57 +02:00
}
2016-06-04 01:08:16 +02:00
2015-12-27 19:00:35 +01:00
public function getEventContributors ( $id ) {
2016-05-13 20:44:16 +02:00
$orgs = $this -> find ( 'all' , array ( 'fields' => array ( 'DISTINCT(org_id)' ), 'conditions' => array ( 'event_id' => $id ), 'order' => false ));
2015-12-27 19:00:35 +01:00
$org_ids = array ();
foreach ( $orgs as $org ) {
$org_ids [] = $org [ 'ShadowAttribute' ][ 'org_id' ];
}
return $org_ids ;
2015-10-16 23:49:04 +02:00
}
2016-06-04 01:08:16 +02:00
2016-01-14 02:46:10 +01:00
2017-05-05 01:01:37 +02:00
/**
* Sends an email to members of the organization that owns the event
* @ param int $id The event id
* @ return boolean False if no email at all was sent , true if at least an email was sent
*/
2016-01-14 02:46:10 +01:00
public function sendProposalAlertEmail ( $id ) {
$this -> Event -> recursive = - 1 ;
$event = $this -> Event -> read ( null , $id );
2016-06-04 01:08:16 +02:00
2016-01-14 02:46:10 +01:00
// If the event has an e-mail lock, return
if ( $event [ 'Event' ][ 'proposal_email_lock' ] == 1 ) {
2017-05-05 01:01:37 +02:00
return false ;
2016-01-14 02:46:10 +01:00
} else {
$this -> setProposalLock ( $id );
}
$this -> User = ClassRegistry :: init ( 'User' );
$this -> User -> recursive = - 1 ;
$orgMembers = $this -> User -> find ( 'all' , array (
'conditions' => array (
'org_id' => $event [ 'Event' ][ 'orgc_id' ],
2016-02-02 15:30:23 +01:00
'contactalert' => 1 ,
'disabled' => 0
2016-01-14 02:46:10 +01:00
),
2016-04-05 18:01:50 +02:00
'fields' => array ( 'email' , 'gpgkey' , 'certif_public' , 'contactalert' , 'id' )
2016-01-14 02:46:10 +01:00
));
2016-06-04 01:08:16 +02:00
2016-01-14 02:46:10 +01:00
$body = " Hello, \n \n " ;
$body .= " A user of another organisation has proposed a change to an event created by you or your organisation. \n \n " ;
$body .= 'To view the event in question, follow this link: ' . Configure :: read ( 'MISP.baseurl' ) . '/events/view/' . $id . " \n " ;
$subject = " [ " . Configure :: read ( 'MISP.org' ) . " MISP] Proposal to event # " . $id ;
2017-05-05 01:01:37 +02:00
$result = false ;
2016-09-04 23:31:24 +02:00
foreach ( $orgMembers as $user ) {
2017-05-05 01:01:37 +02:00
$result = $this -> User -> sendEmail ( $user , $body , $body , $subject ) or $result ;
2016-01-14 02:46:10 +01:00
}
return $result ;
}
2016-06-04 01:08:16 +02:00
2016-01-14 02:46:10 +01:00
public function setProposalLock ( $id , $lock = true ) {
$this -> Event -> recursive = - 1 ;
$event = $this -> Event -> read ( null , $id );
if ( $lock ) {
$event [ 'Event' ][ 'proposal_email_lock' ] = 1 ;
} else {
$event [ 'Event' ][ 'proposal_email_lock' ] = 0 ;
}
$fieldList = array ( 'proposal_email_lock' , 'id' , 'info' );
2017-10-27 12:16:57 +02:00
$event [ 'Event' ][ 'skip_zmq' ] = 1 ;
2016-01-14 02:46:10 +01:00
$this -> Event -> save ( $event , array ( 'fieldList' => $fieldList ));
}
2016-06-04 01:08:16 +02:00
2016-02-17 14:43:33 +01:00
public function generateCorrelation ( $jobId = false ) {
$this -> ShadowAttributeCorrelation = ClassRegistry :: init ( 'ShadowAttributeCorrelation' );
$this -> ShadowAttributeCorrelation -> deleteAll ( array ( 'id !=' => 0 ), false );
// get all proposals..
$proposals = $this -> find ( 'all' , array ( 'recursive' => - 1 , 'conditions' => array ( 'ShadowAttribute.deleted' => 0 , 'ShadowAttribute.proposal_to_delete' => 0 )));
$proposalCount = count ( $proposals );
2016-02-17 14:51:17 +01:00
if ( $jobId && Configure :: read ( 'MISP.background_jobs' )) {
$this -> Job = ClassRegistry :: init ( 'Job' );
$this -> Job -> id = $jobId ;
}
2016-02-17 14:43:33 +01:00
if ( $proposalCount > 0 ) {
foreach ( $proposals as $k => $proposal ) {
$this -> __afterSaveCorrelation ( $proposal [ 'ShadowAttribute' ]);
if ( $jobId && Configure :: read ( 'MISP.background_jobs' ) && $k > 0 && $proposalCount % $k == 10 ) {
2016-02-17 14:49:38 +01:00
$this -> Job -> saveField ( 'progress' , ( $k / $proposalCount * 100 ));
2016-06-04 01:10:45 +02:00
}
2016-02-17 14:43:33 +01:00
}
}
if ( $jobId && Configure :: read ( 'MISP.background_jobs' )) {
$this -> Job -> saveField ( 'progress' , 100 );
$this -> Job -> saveField ( 'status' , 4 );
$this -> Job -> saveField ( 'message' , 'Job done.' );
}
return $proposalCount ;
}
2016-06-04 01:08:16 +02:00
2016-02-17 14:43:33 +01:00
public function upgradeToProposalCorrelation () {
$this -> Log = ClassRegistry :: init ( 'Log' );
if ( ! Configure :: read ( 'MISP.background_jobs' )) {
$this -> Log -> create ();
$this -> Log -> save ( array (
'org' => 'SYSTEM' ,
'model' => 'Server' ,
'model_id' => 0 ,
'email' => 'SYSTEM' ,
'action' => 'update_database' ,
'user_id' => 0 ,
'title' => 'Starting proposal correlation generation' ,
'change' => 'The generation of Proposal correlations as part of the 2.4.20 datamodel upgrade has started'
));
$count = $this -> generateCorrelation ();
$this -> Log -> create ();
if ( is_numeric ( $count )) {
$this -> Log -> save ( array (
'org' => 'SYSTEM' ,
'model' => 'Server' ,
'model_id' => 0 ,
'email' => 'SYSTEM' ,
'action' => 'update_database' ,
'user_id' => 0 ,
'title' => 'Proposal correlation generation complete' ,
'change' => 'The generation of Proposal correlations as part of the 2.4.20 datamodel upgrade is completed. ' . $count . ' proposals used.'
));
} else {
$this -> Log -> save ( array (
'org' => 'SYSTEM' ,
'model' => 'Server' ,
'model_id' => 0 ,
'email' => 'SYSTEM' ,
'action' => 'update_database' ,
'user_id' => 0 ,
'title' => 'Proposal correlation generation failed' ,
'change' => 'The generation of Proposal correlations as part of the 2.4.20 has failed. You can rerun it from the administrative tools.'
));
}
} else {
$job = ClassRegistry :: init ( 'Job' );
$job -> create ();
$data = array (
'worker' => 'default' ,
'job_type' => 'generate proposal correlation' ,
'job_input' => 'All attributes' ,
'retries' => 0 ,
'status' => 1 ,
'org' => 'SYSTEM' ,
'message' => 'Correlating Proposals.' ,
);
$job -> save ( $data );
$jobId = $job -> id ;
$process_id = CakeResque :: enqueue (
'default' ,
'AdminShell' ,
2016-08-15 16:30:37 +02:00
array ( 'jobGenerateShadowAttributeCorrelation' , $jobId ),
true
2016-02-17 14:43:33 +01:00
);
$job -> saveField ( 'process_id' , $process_id );
$this -> Log -> create ();
$this -> Log -> save ( array (
'org' => 'SYSTEM' ,
'model' => 'Server' ,
'model_id' => 0 ,
'email' => 'SYSTEM' ,
'action' => 'update_database' ,
'user_id' => 0 ,
'title' => 'Proposal correlation generation job queued' ,
'change' => 'The job for the generation of Proposal correlations as part of the 2.4.20 datamodel upgrade has been queued'
));
}
}
2016-06-06 10:09:55 +02:00
}