2012-03-15 15:06:45 +01:00
< ? php
2012-09-24 16:02:01 +02:00
2012-03-15 15:06:45 +01:00
App :: uses ( 'AppModel' , 'Model' );
2012-05-22 13:58:37 +02:00
App :: uses ( 'Folder' , 'Utility' );
2012-03-23 20:04:22 +01:00
App :: uses ( 'File' , 'Utility' );
2012-03-15 15:06:45 +01:00
/**
2012-03-26 19:56:44 +02:00
* Attribute Model
2012-03-15 15:06:45 +01:00
*
* @ property Event $Event
*/
2012-03-26 19:56:44 +02:00
class Attribute extends AppModel {
2012-06-28 17:24:12 +02:00
2012-09-24 16:02:01 +02:00
public $combinedKeys = array ( 'event_id' , 'category' , 'type' );
public $name = 'Attribute' ; // TODO general
2012-09-20 11:34:41 +02:00
2012-09-24 16:02:01 +02:00
public $actsAs = array ( 'SysLogLogable.SysLogLogable' => array ( // TODO Audit, logable
'userModel' => 'User' ,
'userKey' => 'user_id' ,
'change' => 'full'
2012-11-29 09:35:57 +01:00
), 'Trim' // => array('fields' => array('value'))
2012-11-26 15:34:54 +01:00
);
2012-09-20 11:34:41 +02:00
2012-03-15 15:06:45 +01:00
/**
* Display field
*
* @ var string
*/
public $displayField = 'value' ;
2012-03-25 15:56:29 +02:00
2012-09-24 16:02:01 +02:00
/**
* Virtual field
*
* @ var array
*/
2012-04-25 13:17:44 +02:00
public $virtualFields = array (
2012-09-18 15:30:32 +02:00
'value' => 'IF (Attribute.value2="", Attribute.value1, CONCAT(Attribute.value1, "|", Attribute.value2))' ,
2012-07-20 13:27:55 +02:00
'category_order' => ' IF ( Attribute . category = " Internal reference " , " a " ,
2012-09-24 16:02:01 +02:00
IF ( Attribute . category = " Antivirus detection " , " b " ,
IF ( Attribute . category = " Payload delivery " , " c " ,
IF ( Attribute . category = " Payload installation " , " d " ,
IF ( Attribute . category = " Artifacts dropped " , " e " ,
IF ( Attribute . category = " Persistence mechanism " , " f " ,
IF ( Attribute . category = " Network activity " , " g " ,
IF ( Attribute . category = " Payload type " , " h " ,
IF ( Attribute . category = " Attribution " , " i " ,
IF ( Attribute . category = " External analysis " , " j " , " k " )))))))))) '
2012-07-20 13:27:55 +02:00
); // TODO hardcoded
2012-04-25 13:17:44 +02:00
2012-05-29 16:53:50 +02:00
/**
2012-09-24 16:02:01 +02:00
* Field Descriptions
2012-09-18 15:30:32 +02:00
* explanations of certain fields to be used in various views
2012-05-29 16:53:50 +02:00
*
2012-09-24 16:02:01 +02:00
* @ public array
2012-05-29 16:53:50 +02:00
*/
2012-09-19 11:05:10 +02:00
public $fieldDescriptions = array (
2012-05-29 16:53:50 +02:00
'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' )
);
2012-05-30 10:24:57 +02:00
2012-10-23 11:28:39 +02:00
public $distributionDescriptions = array (
2012-11-16 15:25:57 +01:00
'Your organization only' => array ( 'desc' => 'This field determines the current distribution of the even' , 'formdesc' => " Only organization members will see the attribute " ),
'This server-only' => array ( 'desc' => 'This field determines the current distribution of the even' , 'formdesc' => " Every organisation on the server can see this attribute " ),
'This Community-only' => array ( 'desc' => 'This field determines the current distribution of the even' , 'formdesc' => " Attribute visible to all on this and _allied_ CyDefSIG instances but will not be shared past it " ),
'Connected communities' => array ( 'desc' => 'This field determines the current distribution of the even' , 'formdesc' => " Attribute visible to CyDefSIG instances with more then two servers but will not be shared past it " ),
'All communities' => array ( 'desc' => 'This field determines the current distribution of the even' , 'formdesc' => " To be distributed to every connected CyDefSIG server " ),
2012-10-23 11:28:39 +02:00
);
2012-06-11 11:01:58 +02:00
// these are definition of possible types + their descriptions and maybe later other behaviors
2012-05-29 16:53:50 +02:00
// e.g. if the attribute should be correlated with others or not
2012-05-30 10:24:57 +02:00
2012-07-10 11:39:43 +02:00
// if these then a category my have upload to be zipped
2012-09-19 11:05:10 +02:00
public $zippedDefinitions = array (
2012-07-10 11:39:43 +02:00
'malware-sample'
);
2012-07-06 13:48:17 +02:00
// if these then a category my have upload
2012-09-19 11:05:10 +02:00
public $uploadDefinitions = array (
2012-07-10 11:39:43 +02:00
'attachment'
2012-07-06 13:48:17 +02:00
);
2012-09-19 11:05:10 +02:00
public $typeDefinitions = array (
2012-05-29 16:53:50 +02:00
'md5' => array ( 'desc' => 'A checksum in md5 format' , 'formdesc' => " You are encouraged to use filename|md5 instead. <br/>A checksum in md5 format, only use this if you don't know the correct filename " ),
'sha1' => array ( 'desc' => 'A checksum in sha1 format' , 'formdesc' => " You are encouraged to use filename|sha1 instead. <br/>A checksum in sha1 format, only use this if you don't know the correct filename " ),
'filename' => array ( 'desc' => 'Filename' ),
'filename|md5' => array ( 'desc' => 'A filename and an md5 hash separated by a |' , 'formdesc' => " A filename and an md5 hash separated by a | (no spaces) " ),
'filename|sha1' => array ( 'desc' => 'A filename and an sha1 hash separated by a |' , 'formdesc' => " A filename and an sha1 hash separated by a | (no spaces) " ),
'ip-src' => array ( 'desc' => " A source IP address of the attacker " ),
'ip-dst' => array ( 'desc' => 'A destination IP address of the attacker or C&C server' , 'formdesc' => " A destination IP address of the attacker or C&C server. <br/>Also set the IDS flag on when this IP is hardcoded in malware " ),
'hostname' => array ( 'desc' => 'A full host/dnsname of an attacker' , 'formdesc' => " A full host/dnsname of an attacker. <br/>Also set the IDS flag on when this hostname is hardcoded in malware " ),
'domain' => array ( 'desc' => 'A domain name used in the malware' , 'formdesc' => " A domain name used in the malware. <br/>Use this instead of hostname when the upper domain is <br/>important or can be used to create links between events. " ),
'email-src' => array ( 'desc' => " The email address (or domainname) used to send the malware. " ),
'email-dst' => array ( 'desc' => " A recipient email address " , 'formdesc' => " A recipient email address that is not related to your constituency. " ),
'email-subject' => array ( 'desc' => " The subject of the email " ),
'email-attachment' => array ( 'desc' => " File name of the email attachment. " ),
'url' => array ( 'desc' => 'url' ),
'user-agent' => array ( 'desc' => " The user-agent used by the malware in the HTTP request. " ),
'regkey' => array ( 'desc' => " Registry key or value " ),
'regkey|value' => array ( 'desc' => " Registry value + data separated by | " ),
'AS' => array ( 'desc' => 'Autonomous system' ),
'snort' => array ( 'desc' => 'An IDS rule in Snort rule-format' , 'formdesc' => " An IDS rule in Snort rule-format. <br/>This rule will be automatically rewritten in the NIDS exports. " ),
'pattern-in-file' => array ( 'desc' => 'Pattern in file that identifies the malware' ),
'pattern-in-traffic' => array ( 'desc' => 'Pattern in network traffic that identifies the malware' ),
'pattern-in-memory' => array ( 'desc' => 'Pattern in memory dump that identifies the malware' ),
2012-10-18 09:56:46 +02:00
'yara' => array ( 'desc' => 'Yara signature' ),
2012-05-29 16:53:50 +02:00
'vulnerability' => array ( 'desc' => 'A reference to the vulnerability used in the exploit' ),
'attachment' => array ( 'desc' => 'Attachment with external information' , 'formdesc' => " Please upload files using the <em>Upload Attachment</em> button. " ),
'malware-sample' => array ( 'desc' => 'Attachment containing encrypted malware sample' , 'formdesc' => " Please upload files using the <em>Upload Attachment</em> button. " ),
'link' => array ( 'desc' => 'Link to an external information' ),
'comment' => array ( 'desc' => 'Comment or description in a human language' , 'formdesc' => 'Comment or description in a human language. <br/> This will not be correlated with other attributes (NOT IMPLEMENTED YET)' ),
'text' => array ( 'desc' => 'Name, ID or a reference' ),
'other' => array ( 'desc' => 'Other attribute' )
);
2012-05-30 10:24:57 +02:00
2012-05-29 16:53:50 +02:00
// definitions of categories
2012-09-19 11:05:10 +02:00
public $categoryDefinitions = array (
2012-05-30 17:13:35 +02:00
'Internal reference' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Reference used by the publishing party (e.g. ticket number)' ,
'types' => array ( 'link' , 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Antivirus detection' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'All the info about how the malware is detected by the antivirus products' ,
'formdesc' => 'List of anti-virus vendors detecting the malware or information on detection performance (e.g. 13/43 or 67%).<br/>Attachment with list of detection or link to VirusTotal could be placed here as well.' ,
'types' => array ( 'link' , 'comment' , 'text' , 'attachment' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Payload delivery' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about how the malware is delivered' ,
'formdesc' => 'Information about the way the malware payload is initially delivered, <br/>for example information about the email or web-site, vulnerability used, originating IP etc. <br/>Malware sample itself should be attached here.' ,
2012-10-18 09:56:46 +02:00
'types' => array ( 'md5' , 'sha1' , 'filename' , 'filename|md5' , 'filename|sha1' , 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'email-src' , 'email-dst' , 'email-subject' , 'email-attachment' , 'url' , 'ip-dst' , 'user-agent' , 'AS' , 'pattern-in-file' , 'pattern-in-traffic' , 'yara' , 'attachment' , 'malware-sample' , 'link' , 'comment' , 'text' , 'vulnerability' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Artifacts dropped' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Any artifact (files, registry keys etc.) dropped by the malware or other modifications to the system' ,
2012-10-18 09:56:46 +02:00
'types' => array ( 'md5' , 'sha1' , 'filename' , 'filename|md5' , 'filename|sha1' , 'regkey' , 'regkey|value' , 'pattern-in-file' , 'pattern-in-memory' , 'yara' , 'attachment' , 'malware-sample' , 'comment' , 'text' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Payload installation' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Info on where the malware gets installed in the system' ,
'formdesc' => 'Location where the payload was placed in the system and the way it was installed.<br/>For example, a filename|md5 type attribute can be added here like this:<br/>c:\\windows\\system32\\malicious.exe|41d8cd98f00b204e9800998ecf8427e.' ,
2012-10-18 09:56:46 +02:00
'types' => array ( 'md5' , 'sha1' , 'filename' , 'filename|md5' , 'filename|sha1' , 'pattern-in-file' , 'pattern-in-traffic' , 'pattern-in-memory' , 'yara' , 'vulnerability' , 'attachment' , 'malware-sample' , 'comment' , 'text' , 'other' )
2012-09-18 15:30:32 +02:00
),
2012-05-30 17:13:35 +02:00
'Persistence mechanism' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Mechanisms used by the malware to start at boot' ,
'formdesc' => 'Mechanisms used by the malware to start at boot.<br/>This could be a registry key, legitimate driver modification, LNK file in startup' ,
'types' => array ( 'filename' , 'regkey' , 'regkey|value' , 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Network activity' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about network traffic generated by the malware' ,
'types' => array ( 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'email-dst' , 'url' , 'user-agent' , 'AS' , 'snort' , 'pattern-in-file' , 'pattern-in-traffic' , 'attachment' , 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Payload type' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Information about the final payload(s)' ,
'formdesc' => 'Information about the final payload(s).<br/>Can contain a function of the payload, e.g. keylogger, RAT, or a name if identified, such as Poison Ivy.' ,
'types' => array ( 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Attribution' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Identification of the group, organisation, or coountry behind the attack' ,
'types' => array ( 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'External analysis' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Any other result from additional analysis of the malware like tools output' ,
'formdesc' => 'Any other result from additional analysis of the malware like tools output<br/>Examples: pdf-parser output, automated sandbox analysis, reverse engineering report.' ,
'types' => array ( 'md5' , 'sha1' , 'filename' , 'filename|md5' , 'filename|sha1' , 'ip-src' , 'ip-dst' , 'hostname' , 'domain' , 'url' , 'user-agent' , 'regkey' , 'regkey|value' , 'AS' , 'snort' , 'pattern-in-file' , 'pattern-in-traffic' , 'pattern-in-memory' , 'vulnerability' , 'attachment' , 'malware-sample' , 'link' , 'comment' , 'text' , 'other' )
),
2012-05-30 17:13:35 +02:00
'Other' => array (
2012-09-18 15:30:32 +02:00
'desc' => 'Attributes that are not part of any other category' ,
'types' => array ( 'comment' , 'text' , 'other' )
)
2012-05-29 16:53:50 +02:00
);
2012-05-30 10:24:57 +02:00
2012-09-24 16:02:01 +02:00
public $order = array ( " Attribute.event_id " => " DESC " , " Attribute.type " => " ASC " );
2012-05-30 10:24:57 +02:00
2012-03-15 15:06:45 +01:00
/**
* Validation rules
*
* @ var array
*/
public $validate = array (
'event_id' => array (
'numeric' => array (
'rule' => array ( 'numeric' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'type' => array (
2012-05-29 16:53:50 +02:00
// currently when adding a new attribute type we need to change it in both places
2012-05-31 17:12:26 +02:00
'rule' => array ( 'validateTypeValue' ),
'message' => 'Options depend on the selected category.' ,
2012-03-15 15:06:45 +01:00
//'allowEmpty' => false,
'required' => true ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
2012-03-25 15:56:29 +02:00
2012-03-15 15:06:45 +01:00
),
2012-09-19 11:05:10 +02:00
// this could be initialized from categoryDefinitions but dunno how at the moment
2012-09-18 15:30:32 +02:00
'category' => array (
2012-03-27 14:02:49 +02:00
'rule' => array ( 'inList' , array (
2012-04-13 10:53:53 +02:00
'Internal reference' ,
2012-05-29 17:19:36 +02:00
'Antivirus detection' ,
2012-09-18 15:30:32 +02:00
'Payload delivery' ,
'Payload installation' ,
'Artifacts dropped' ,
'Persistence mechanism' ,
'Network activity' ,
'Payload type' ,
'Attribution' ,
'External analysis' ,
'Other' ,
'' // FIXME remove this once all attributes have a category. Otherwise sigs without category are not shown in the list
)),
'message' => 'Options : Payload delivery, Antivirus detection, Payload installation, Files dropped ...'
2012-03-23 20:04:22 +01:00
),
2012-03-15 15:06:45 +01:00
'value' => array (
'notempty' => array (
'rule' => array ( 'notempty' ),
'message' => 'Please fill in this field' ,
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'userdefined' => array (
2012-03-26 19:56:44 +02:00
'rule' => array ( 'validateAttributeValue' ),
2012-03-15 15:06:45 +01:00
'message' => 'Value not in the right type/format. Please double check the value or select "other" for a type.' ,
//'allowEmpty' => false,
//'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
2012-09-18 15:30:32 +02:00
'unique' => array (
'rule' => array ( 'valueIsUnique' ),
'message' => 'A similar attribute already exists for this event.' ,
//'allowEmpty' => false,
//'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
2012-04-10 15:47:42 +02:00
),
2012-03-15 15:06:45 +01:00
),
'to_ids' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'uuid' => array (
'uuid' => array (
'rule' => array ( 'uuid' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
2012-03-20 13:40:58 +01:00
'revision' => array (
'numeric' => array (
'rule' => array ( 'numeric' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
//'required' => false,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
2012-09-18 15:30:32 +02:00
'private' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
//'message' => 'Your custom message here',
'allowEmpty' => true ,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
2012-03-20 13:40:58 +01:00
),
2012-03-15 15:06:45 +01:00
);
2012-10-17 14:45:26 +02:00
public function __construct ( $id = false , $table = null , $ds = null ) {
parent :: __construct ( $id , $table , $ds );
if ( 'true' == Configure :: read ( 'CyDefSIG.private' )) {
$this -> virtualFields = Set :: merge ( $this -> virtualFields , array (
2012-11-16 15:25:57 +01:00
//'distribution' => 'IF (Attribute.private=true, "Your organization only", IF (Attribute.cluster=true, "This Community-only", "All communities"))',
'distribution' => 'IF (Attribute.private=true AND Attribute.cluster=false, "Your organization only", IF (Attribute.private=true AND Attribute.cluster=true, "This server-only", IF (Attribute.private=false AND Attribute.cluster=true, "This Community-only", IF (Attribute.communitie=true, "Connected communities" , "All communities"))))' ,
2012-10-17 14:45:26 +02:00
));
$this -> fieldDescriptions = Set :: merge ( $this -> fieldDescriptions , array (
2012-10-23 11:28:39 +02:00
'distribution' => array ( 'desc' => 'This fields indicates the intended distribution of the attribute (same as when adding an event, see Add Event)' ),
2012-10-17 14:45:26 +02:00
));
$this -> validate = Set :: merge ( $this -> validate , array (
'cluster' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
2012-11-16 15:25:57 +01:00
'communitie' => array (
'boolean' => array (
'rule' => array ( 'boolean' ),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
2012-10-23 11:28:39 +02:00
'distribution' => array (
2012-11-16 15:25:57 +01:00
'rule' => array ( 'inList' , array ( " Your organization only " , " This server-only " , " This Community-only " , " Connected communities " , " All communities " )),
2012-10-17 14:45:26 +02:00
//'message' => 'Your custom message here',
'allowEmpty' => false ,
'required' => false ,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
));
}
}
2012-03-15 15:06:45 +01:00
//The Associations below have been created with all possible keys, those that are not needed can be removed
2012-05-30 10:24:57 +02:00
2012-03-15 15:06:45 +01:00
/**
* belongsTo associations
*
* @ var array
*/
public $belongsTo = array (
'Event' => array (
'className' => 'Event' ,
'foreignKey' => 'event_id' ,
'conditions' => '' ,
'fields' => '' ,
2012-11-14 16:14:04 +01:00
'order' => '' ,
'counterCache' => true
2012-03-15 15:06:45 +01:00
)
);
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
/**
* beforeSave
*
* @ throws InternalErrorException
* @ return bool always true
*/
2012-11-23 08:57:34 +01:00
public function beforeSave ( $options = array ()) {
2012-09-18 15:30:32 +02:00
// increment the revision number
if ( empty ( $this -> data [ 'Attribute' ][ 'revision' ])) {
$this -> data [ 'Attribute' ][ 'revision' ] = 0 ;
}
$this -> data [ 'Attribute' ][ 'revision' ] = 1 + $this -> data [ 'Attribute' ][ 'revision' ];
// explode value of composite type in value1 and value2
// or copy value to value1 if not composite type
if ( ! empty ( $this -> data [ 'Attribute' ][ 'type' ])) {
2012-09-19 11:05:10 +02:00
$compositeTypes = $this -> getCompositeTypes ();
2012-09-18 15:30:32 +02:00
// explode composite types in value1 and value2
$pieces = explode ( '|' , $this -> data [ 'Attribute' ][ 'value' ]);
2012-09-19 11:05:10 +02:00
if ( in_array ( $this -> data [ 'Attribute' ][ 'type' ], $compositeTypes )) {
2012-09-18 15:30:32 +02:00
if ( 2 != count ( $pieces )) {
throw new InternalErrorException ( 'Composite type, but value not explodable' );
}
$this -> data [ 'Attribute' ][ 'value1' ] = $pieces [ 0 ];
$this -> data [ 'Attribute' ][ 'value2' ] = $pieces [ 1 ];
} else {
$total = implode ( '|' , $pieces );
$this -> data [ 'Attribute' ][ 'value1' ] = $total ;
$this -> data [ 'Attribute' ][ 'value2' ] = '' ;
}
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
// always return true after a beforeSave()
return true ;
2012-03-20 13:40:58 +01:00
}
2012-03-25 15:56:29 +02:00
2012-11-23 08:57:34 +01:00
public function afterSave ( $created ) {
2012-09-18 15:30:32 +02:00
if ( 'db' == Configure :: read ( 'CyDefSIG.correlation' )) {
// update correlation..
2012-09-24 09:02:09 +02:00
$this -> __afterSaveCorrelation ( $this -> data [ 'Attribute' ]);
2012-09-18 15:30:32 +02:00
}
$result = true ;
// if the 'data' field is set on the $this->data then save the data to the correct file
if ( isset ( $this -> data [ 'Attribute' ][ 'type' ]) && $this -> typeIsAttachment ( $this -> data [ 'Attribute' ][ 'type' ]) && ! empty ( $this -> data [ 'Attribute' ][ 'data' ])) {
$result = $result && $this -> saveBase64EncodedAttachment ( $this -> data [ 'Attribute' ]);
}
return $result ;
2012-05-22 13:58:37 +02:00
}
2012-11-23 08:57:34 +01:00
public function beforeDelete ( $cascade = true ) {
2012-09-18 15:30:32 +02:00
// delete attachments from the disk
$this -> read (); // first read the attribute from the db
if ( $this -> typeIsAttachment ( $this -> data [ 'Attribute' ][ 'type' ])) {
// FIXME secure this filesystem access/delete by not allowing to change directories or go outside of the directory container.
// only delete the file if it exists
$filepath = APP . " files " . DS . $this -> data [ 'Attribute' ][ 'event_id' ] . DS . $this -> data [ 'Attribute' ][ 'id' ];
$file = new File ( $filepath );
if ( $file -> exists ()) {
if ( ! $file -> delete ()) {
throw new InternalErrorException ( 'Delete of file attachment failed. Please report to administrator.' );
}
}
}
if ( 'db' == Configure :: read ( 'CyDefSIG.correlation' )) {
// update correlation..
2012-09-24 09:02:09 +02:00
$this -> __beforeDeleteCorrelation ( $this -> data [ 'Attribute' ][ 'id' ]);
2012-09-18 15:30:32 +02:00
}
2012-03-23 20:04:22 +01:00
}
2012-03-25 15:56:29 +02:00
2012-10-17 14:45:26 +02:00
public function massageData ( & $data ) {
2012-10-23 11:28:39 +02:00
switch ( $data [ 'Attribute' ][ 'distribution' ]) {
2012-11-16 15:25:57 +01:00
case 'Your organization only' :
2012-10-17 14:45:26 +02:00
$data [ 'Attribute' ][ 'private' ] = true ;
$data [ 'Attribute' ][ 'cluster' ] = false ;
2012-11-16 15:25:57 +01:00
$data [ 'Attribute' ][ 'communitie' ] = false ;
break ;
case 'This server-only' : // TODO
$data [ 'Attribute' ][ 'private' ] = true ;
$data [ 'Attribute' ][ 'cluster' ] = true ;
$data [ 'Attribute' ][ 'communitie' ] = false ;
2012-10-17 14:45:26 +02:00
break ;
2012-11-16 15:25:57 +01:00
case 'This Community-only' :
2012-10-17 14:45:26 +02:00
$data [ 'Attribute' ][ 'private' ] = false ;
$data [ 'Attribute' ][ 'cluster' ] = true ;
2012-11-16 15:25:57 +01:00
$data [ 'Attribute' ][ 'communitie' ] = false ;
break ;
case 'Connected communities' : // TODO
$data [ 'Attribute' ][ 'private' ] = false ;
$data [ 'Attribute' ][ 'cluster' ] = false ;
$data [ 'Attribute' ][ 'communitie' ] = true ;
2012-10-18 11:40:12 +02:00
break ;
2012-11-16 15:25:57 +01:00
case 'All communities' :
2012-10-17 14:45:26 +02:00
$data [ 'Attribute' ][ 'private' ] = false ;
$data [ 'Attribute' ][ 'cluster' ] = false ;
2012-11-16 15:25:57 +01:00
$data [ 'Attribute' ][ 'communitie' ] = false ;
2012-10-17 14:45:26 +02:00
break ;
}
return $data ;
}
2012-11-23 08:57:34 +01:00
public function beforeValidate ( $options = array ()) {
2012-11-26 15:34:54 +01:00
parent :: beforeValidate ();
2012-09-18 15:30:32 +02:00
// remove leading and trailing blanks
2012-11-26 15:34:54 +01:00
//$this->trimStringFields(); // TODO
2012-09-18 15:30:32 +02:00
$this -> data [ 'Attribute' ][ 'value' ] = trim ( $this -> data [ 'Attribute' ][ 'value' ]);
if ( ! isset ( $this -> data [ 'Attribute' ][ 'type' ])) {
return false ;
}
switch ( $this -> data [ 'Attribute' ][ 'type' ]) {
// lowercase these things
case 'md5' :
case 'sha1' :
case 'domain' :
case 'hostname' :
$this -> data [ 'Attribute' ][ 'value' ] = strtolower ( $this -> data [ 'Attribute' ][ 'value' ]);
break ;
case 'filename|md5' :
case 'filename|sha1' :
$pieces = explode ( '|' , $this -> data [ 'Attribute' ][ 'value' ]);
$this -> data [ 'Attribute' ][ 'value' ] = $pieces [ 0 ] . '|' . strtolower ( $pieces [ 1 ]);
break ;
}
// generate UUID if it doesn't exist
if ( empty ( $this -> data [ 'Attribute' ][ 'uuid' ])) {
$this -> data [ 'Attribute' ][ 'uuid' ] = String :: uuid ();
}
// always return true, otherwise the object cannot be saved
return true ;
2012-03-25 15:56:29 +02:00
}
2012-09-18 15:30:32 +02:00
public function valueIsUnique ( $fields ) {
$value = $fields [ 'value' ];
2012-09-19 11:05:10 +02:00
$eventId = $this -> data [ 'Attribute' ][ 'event_id' ];
2012-09-18 15:30:32 +02:00
$type = $this -> data [ 'Attribute' ][ 'type' ];
2012-09-19 11:05:10 +02:00
$toIds = $this -> data [ 'Attribute' ][ 'to_ids' ];
2012-09-18 15:30:32 +02:00
$category = $this -> data [ 'Attribute' ][ 'category' ];
// check if the attribute already exists in the same event
2012-09-19 11:05:10 +02:00
$conditions = array ( 'Attribute.event_id' => $eventId ,
2012-09-18 15:30:32 +02:00
'Attribute.type' => $type ,
'Attribute.category' => $category ,
'Attribute.value' => $value
);
if ( isset ( $this -> data [ 'Attribute' ][ 'id' ])) {
$conditions [ 'Attribute.id !=' ] = $this -> data [ 'Attribute' ][ 'id' ];
}
$params = array ( 'recursive' => 0 ,
'conditions' => $conditions ,
);
if ( 0 != $this -> find ( 'count' , $params )) {
return false ;
}
// Say everything is fine
return true ;
2012-04-10 15:47:42 +02:00
}
2012-09-18 15:30:32 +02:00
public function validateTypeValue ( $fields ) {
$category = $this -> data [ 'Attribute' ][ 'category' ];
2012-09-19 11:05:10 +02:00
if ( isset ( $this -> categoryDefinitions [ $category ][ 'types' ])) {
return in_array ( $fields [ 'type' ], $this -> categoryDefinitions [ $category ][ 'types' ]);
2012-09-18 15:30:32 +02:00
}
return false ;
2012-05-31 17:12:26 +02:00
}
2012-09-24 08:27:22 +02:00
public function validateAttributeValue ( $fields ) {
2012-09-18 15:30:32 +02:00
$value = $fields [ 'value' ];
2012-09-19 11:24:12 +02:00
$returnValue = false ;
2012-09-18 15:30:32 +02:00
// check data validation
switch ( $this -> data [ 'Attribute' ][ 'type' ]) {
case 'md5' :
if ( preg_match ( " #^[0-9a-f] { 32} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Checksum has invalid length or format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'sha1' :
if ( preg_match ( " #^[0-9a-f] { 40} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Checksum has invalid length or format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'filename' :
// no newline
2012-10-03 11:09:30 +02:00
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'filename|md5' :
// no newline
if ( preg_match ( " #^.+ \ |[0-9a-f] { 32} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Checksum has invalid length or format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'filename|sha1' :
// no newline
if ( preg_match ( " #^.+ \ |[0-9a-f] { 40} $ # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Checksum has invalid length or format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'ip-src' :
$parts = explode ( " / " , $value );
// [0] = the ip
// [1] = the network address
if ( count ( $parts ) <= 2 ) {
// ipv4 and ipv6 matching
if ( filter_var ( $parts [ 0 ], FILTER_VALIDATE_IP )) {
// ip is validated, now check if we have a valid network mask
if ( empty ( $parts [ 1 ])) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
} else {
if ( is_numeric ( $parts [ 1 ]) && $parts [ 1 ] < 129 ) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
}
}
}
2012-09-19 11:24:12 +02:00
if ( ! $returnValue ) {
$returnValue = 'IP address has invalid format. Please double check the value or select "other" for a type.' ;
}
2012-09-18 15:30:32 +02:00
break ;
case 'ip-dst' :
$parts = explode ( " / " , $value );
// [0] = the ip
// [1] = the network address
if ( count ( $parts ) <= 2 ) {
// ipv4 and ipv6 matching
if ( filter_var ( $parts [ 0 ], FILTER_VALIDATE_IP )) {
// ip is validated, now check if we have a valid network mask
if ( empty ( $parts [ 1 ])) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
} else {
if ( is_numeric ( $parts [ 1 ]) && $parts [ 1 ] < 129 ) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
}
}
}
2012-09-19 11:24:12 +02:00
if ( ! $returnValue ) {
$returnValue = 'IP address has invalid format. Please double check the value or select "other" for a type.' ;
}
2012-09-18 15:30:32 +02:00
break ;
case 'hostname' :
case 'domain' :
if ( preg_match ( " #^[A-Z0-9.-]+ \ .[A-Z] { 2,4} $ #i " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Domain name has invalid format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'email-src' :
// we don't use the native function to prevent issues with partial email addresses
if ( preg_match ( " #^[A-Z0-9._%+-]*@[A-Z0-9.-]+ \ .[A-Z] { 2,4} $ #i " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Email address has invalid format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'email-dst' :
// we don't use the native function to prevent issues with partial email addresses
if ( preg_match ( " #^[A-Z0-9._%+-]*@[A-Z0-9.-]+ \ .[A-Z] { 2,4} $ #i " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
} else {
$returnValue = 'Email address has invalid format. Please double check the value or select "other" for a type.' ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'email-subject' :
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'email-attachment' :
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'url' :
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'user-agent' :
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'regkey' :
// no newline
if ( ! preg_match ( " # \n # " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'regkey|value' :
// no newline
if ( ! preg_match ( " #.+ \ |.+# " , $value )) {
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
}
break ;
case 'snort' :
// no validation yet. TODO implement data validation on snort attribute type
case 'other' :
2012-09-19 11:24:12 +02:00
$returnValue = true ;
2012-09-18 15:30:32 +02:00
break ;
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
// default action is to return false
2012-09-24 08:27:22 +02:00
if ( ! $returnValue ) {
$returnValue = true ;
}
2012-09-19 11:24:12 +02:00
return $returnValue ;
2012-03-15 15:06:45 +01:00
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function getCompositeTypes () {
// build the list of composite Attribute.type dynamically by checking if type contains a |
// default composite types
2012-09-19 11:05:10 +02:00
$compositeTypes = array ( 'malware-sample' ); // TODO hardcoded composite
2012-09-18 15:30:32 +02:00
// dynamically generated list
2012-09-19 11:05:10 +02:00
foreach ( array_keys ( $this -> typeDefinitions ) as $type ) {
2012-09-18 15:30:32 +02:00
$pieces = explode ( '|' , $type );
if ( 2 == count ( $pieces )) {
2012-09-19 11:05:10 +02:00
$compositeTypes [] = $type ;
2012-09-18 15:30:32 +02:00
}
}
2012-09-19 11:05:10 +02:00
return $compositeTypes ;
2012-09-18 15:30:32 +02:00
}
2012-03-25 15:56:29 +02:00
2012-03-26 19:56:44 +02:00
public function isOwnedByOrg ( $attributeid , $org ) {
2012-09-18 15:30:32 +02:00
$this -> id = $attributeid ;
$this -> read ();
return $this -> data [ 'Event' ][ 'org' ] === $org ;
2012-03-20 14:57:52 +01:00
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function getRelatedAttributes ( $attribute , $fields = array ()) {
// LATER getRelatedAttributes($attribute) this might become a performance bottleneck
// exclude these specific categories to be linked
switch ( $attribute [ 'category' ]) {
case 'Antivirus detection' :
return null ;
}
// exclude these specific types to be linked
switch ( $attribute [ 'type' ]) {
case 'other' :
case 'comment' :
return null ;
}
// prepare the conditions
$conditions = array (
'Attribute.event_id !=' => $attribute [ 'event_id' ],
//'Attribute.type' => $attribute['type'], // do not filter on type
);
if ( empty ( $attribute [ 'value1' ])) { // prevent issues with empty fields
return null ;
}
if ( empty ( $attribute [ 'value2' ])) {
// no value2, only search for value 1
$conditions [ 'OR' ] = array (
'Attribute.value1' => $attribute [ 'value1' ],
'Attribute.value2' => $attribute [ 'value1' ],
);
} else {
// value2 also set, so search for both
$conditions [ 'OR' ] = array (
'Attribute.value1' => array ( $attribute [ 'value1' ], $attribute [ 'value2' ]),
'Attribute.value2' => array ( $attribute [ 'value1' ], $attribute [ 'value2' ]),
);
}
// do the search
if ( empty ( $fields )) {
$fields = array ( 'Attribute.*' );
}
2012-09-19 11:05:10 +02:00
$similarEvents = $this -> find ( 'all' , array ( 'conditions' => $conditions ,
2012-09-18 15:30:32 +02:00
'fields' => $fields ,
'recursive' => 0 ,
'group' => array ( 'Attribute.event_id' ),
'order' => 'Attribute.event_id DESC' , )
);
2012-09-19 11:05:10 +02:00
return $similarEvents ;
2012-03-15 15:06:45 +01:00
}
2012-03-25 15:56:29 +02:00
2012-09-18 15:30:32 +02:00
public function typeIsMalware ( $type ) {
2012-09-19 11:05:10 +02:00
if ( in_array ( $type , $this -> zippedDefinitions )) {
2012-09-18 15:30:32 +02:00
return true ;
} else {
return false ;
}
2012-07-10 11:39:43 +02:00
}
2012-09-20 11:34:41 +02:00
2012-09-18 15:30:32 +02:00
public function typeIsAttachment ( $type ) {
2012-09-19 11:05:10 +02:00
if (( in_array ( $type , $this -> zippedDefinitions )) || ( in_array ( $type , $this -> uploadDefinitions ))) {
2012-09-18 15:30:32 +02:00
return true ;
} else {
return false ;
}
2012-05-21 15:20:25 +02:00
}
2012-09-20 11:34:41 +02:00
2012-09-18 15:30:32 +02:00
public function base64EncodeAttachment ( $attribute ) {
$filepath = APP . " files " . DS . $attribute [ 'event_id' ] . DS . $attribute [ 'id' ];
$file = new File ( $filepath );
if ( ! $file -> exists ()) {
return '' ;
}
$content = $file -> read ();
return base64_encode ( $content );
2012-05-21 15:20:25 +02:00
}
2012-09-18 15:30:32 +02:00
public function saveBase64EncodedAttachment ( $attribute ) {
2012-09-19 11:05:10 +02:00
$rootDir = APP . DS . " files " . DS . $attribute [ 'event_id' ];
$dir = new Folder ( $rootDir , true ); // create directory structure
$destpath = $rootDir . DS . $attribute [ 'id' ];
2012-09-18 15:30:32 +02:00
$file = new File ( $destpath , true ); // create the file
2012-09-19 11:05:10 +02:00
$decodedData = base64_decode ( $attribute [ 'data' ]); // decode
if ( $file -> write ( $decodedData )) { // save the data
2012-09-18 15:30:32 +02:00
return true ;
} else {
// error
return false ;
}
2012-05-22 13:58:37 +02:00
}
2012-08-22 16:04:55 +02:00
/**
* add_attachment method
*
* @ return void
*/
2012-10-17 10:42:09 +02:00
public function uploadAttachment ( $fileP , $realFileName , $malware , $eventId = null , $category = null , $extraPath = '' , $fullFileName = '' ) {
2012-09-24 16:02:01 +02:00
// Check if there were problems with the file upload
// only keep the last part of the filename, this should prevent directory attacks
$filename = basename ( $fileP );
$tmpfile = new File ( $fileP );
// save the file-info in the database
$this -> create ();
$this -> data [ 'Attribute' ][ 'event_id' ] = $eventId ;
if ( $malware ) {
2012-11-14 17:16:36 +01:00
$md5 = ! $tmpfile -> size () ? md5_file ( $fileP ) : $tmpfile -> md5 ();
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'category' ] = $category ? $category : " Payload delivery " ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'type' ] = " malware-sample " ;
2012-11-14 16:14:04 +01:00
$this -> data [ 'Attribute' ][ 'value' ] = $fullFileName ? $fullFileName . '|' . $md5 : $filename . '|' . $md5 ; // TODO gives problems with bigger files
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'to_ids' ] = 1 ; // LATER let user choose to send this to IDS
} else {
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'category' ] = $category ? $category : " Artifacts dropped " ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'type' ] = " attachment " ;
2012-10-17 10:42:09 +02:00
$this -> data [ 'Attribute' ][ 'value' ] = $fullFileName ? $fullFileName : $realFileName ;
2012-09-24 16:02:01 +02:00
$this -> data [ 'Attribute' ][ 'to_ids' ] = 0 ;
}
if ( $this -> save ( $this -> data )) {
// attribute saved correctly in the db
} else {
// do some?
}
// 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
$rootDir = APP . DS . " files " . DS . $eventId ;
$dir = new Folder ( $rootDir , true );
// move the file to the correct location
$destpath = $rootDir . DS . $this -> getId (); // id of the new attribute in the database
$file = new File ( $destpath );
$zipfile = new File ( $destpath . '.zip' );
2012-10-17 10:42:09 +02:00
$fileInZip = new File ( $rootDir . DS . $extraPath . $filename ); // FIXME do sanitization of the filename
2012-09-24 16:02:01 +02:00
// zip and password protect the malware files
if ( $malware ) {
// TODO check if CakePHP has no easy/safe wrapper to execute commands
$execRetval = '' ;
$execOutput = array ();
exec ( " zip -j -P infected " . $zipfile -> path . ' "' . addslashes ( $fileInZip -> path ) . '"' , $execOutput , $execRetval );
if ( $execRetval != 0 ) { // not EXIT_SUCCESS
// do some?
};
$fileInZip -> delete (); // delete the original not-zipped-file
rename ( $zipfile -> path , $file -> path ); // rename the .zip to .nothing
} else {
$fileAttach = new File ( $fileP );
rename ( $fileAttach -> path , $file -> path );
}
2012-08-22 16:04:55 +02:00
}
2012-09-20 11:34:41 +02:00
2012-09-24 09:02:09 +02:00
private function __afterSaveCorrelation ( $attribute ) {
2012-11-13 14:13:38 +01:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
2012-11-15 15:53:07 +01:00
$dummy = $this -> Correlation -> deleteAll ( array ( 'OR' => array ( 'Correlation.attribute_id' => $attribute )));
2012-11-13 14:13:38 +01:00
$dummy = $this -> Correlation -> deleteAll ( array ( 'OR' => array ( 'Correlation.1_attribute_id' => $attribute )));
2012-08-03 12:00:16 +02:00
// re-add
2012-11-13 14:13:38 +01:00
$this -> setRelatedAttributes ( $attribute , array ( 'Attribute.id' , 'Attribute.event_id' , 'Attribute.private' , 'Attribute.cluster' , 'Event.date' , 'Event.org' ));
// update where refered..
$this -> updateRelatedAttributes ( $attribute , array ( 'Attribute.id' , 'Attribute.event_id' , 'Attribute.private' , 'Attribute.cluster' , 'Event.date' , 'Event.org' ));
2012-08-03 12:00:16 +02:00
}
2012-09-24 09:02:09 +02:00
private function __beforeDeleteCorrelation ( $attribute ) {
2012-08-03 12:00:16 +02:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
$dummy = $this -> Correlation -> deleteAll ( array ( 'OR' => array (
2012-09-18 15:30:32 +02:00
'Correlation.1_attribute_id' => $attribute ,
'Correlation.attribute_id' => $attribute ))
2012-08-03 12:00:16 +02:00
);
}
2012-09-18 15:30:32 +02:00
/**
* return an array containing 'double-values'
*
* @ return array ()
*/
public function doubleAttributes () {
2012-08-03 12:00:16 +02:00
$doubleAttributes = array ();
2012-05-22 13:58:37 +02:00
2012-09-19 11:05:10 +02:00
$similarValue1 = $this -> find ( 'all' , array ( 'conditions' => array (),
2012-09-18 15:30:32 +02:00
'fields' => 'value1' ,
'recursive' => 0 ,
'group' => 'Attribute.value1 HAVING count(1)>1' ));
2012-09-19 11:05:10 +02:00
$similarValue2 = $this -> find ( 'all' , array ( 'conditions' => array (),
2012-09-18 15:30:32 +02:00
'fields' => 'value2' ,
'recursive' => 0 ,
'group' => 'Attribute.value2 HAVING count(1)>1' ));
2012-09-19 11:05:10 +02:00
$similarValues = $this -> find ( 'all' , array ( 'joins' => array ( array (
2012-08-03 12:00:16 +02:00
'table' => 'attributes' ,
'alias' => 'att2' ,
2012-09-18 15:30:32 +02:00
'type' => 'INNER' ,
2012-08-03 12:00:16 +02:00
'conditions' => array ( 'Attribute.value2 = att2.value1' ))),
'fields' => array ( 'att2.value1' )));
2012-09-19 11:05:10 +02:00
$doubleAttributes = array_merge ( $similarValue1 , $similarValue2 );
$doubleAttributes = array_merge ( $doubleAttributes , $similarValues );
2012-08-03 12:00:16 +02:00
$double = array ();
2012-09-18 15:30:32 +02:00
foreach ( $doubleAttributes as $key => $doubleAttribute ) {
2012-08-03 12:00:16 +02:00
$v = isset ( $doubleAttribute [ 'Attribute' ]) ? $doubleAttribute [ 'Attribute' ] : $doubleAttribute [ 'att2' ];
$v = isset ( $v [ 'value1' ]) ? $v [ 'value1' ] : $v [ 'value2' ];
if ( $v != '' ) {
$double [] = $v ;
}
}
return $double ;
}
2012-11-13 14:13:38 +01:00
public function updateRelatedAttributes ( $attribute , $fields = array ()) {
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
// update related
$attributes = $this -> Correlation -> find ( 'all' , array ( 'recursive' => 0 , 'conditions' => array ( 'attribute_id' => $attribute [ 'id' ])));
foreach ( $attributes as $attributeFound ) {
$this -> Correlation -> read ( null , $attributeFound [ 'Correlation' ][ 'id' ]);
$this -> Correlation -> set ( array (
2012-11-14 16:14:04 +01:00
'private' => isset ( $attribute [ 'private' ]) ? $attribute [ 'private' ] : false ,
'cluster' => isset ( $attribute [ 'cluster' ]) ? $attribute [ 'cluster' ] : false ,
2012-11-13 14:13:38 +01:00
));
$this -> Correlation -> save ();
}
// update relating
$attributes = $this -> Correlation -> find ( 'all' , array ( 'recursive' => 0 , 'conditions' => array ( '1_attribute_id' => $attribute [ 'id' ])));
foreach ( $attributes as $attributeFound ) {
$this -> Correlation -> read ( null , $attributeFound [ 'Correlation' ][ 'id' ]);
$this -> Correlation -> set ( array (
2012-11-14 16:14:04 +01:00
'1_private' => isset ( $attribute [ 'private' ]) ? $attribute [ 'private' ] : false ,
2012-11-13 14:13:38 +01:00
));
$this -> Correlation -> save ();
}
// TODO what if value1/2 changes??
}
2012-11-15 15:53:07 +01:00
public function setInitialRelatedAttributes ( $attribute , $fields = array ()) {
2012-08-03 12:00:16 +02:00
$this -> Event = ClassRegistry :: init ( 'Event' );
$relatedAttributes = $this -> getRelatedAttributes ( $attribute , $fields );
if ( $relatedAttributes ) {
2012-11-14 11:28:42 +01:00
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
2012-08-03 12:00:16 +02:00
foreach ( $relatedAttributes as $relatedAttribute ) {
2012-11-14 11:28:42 +01:00
2012-08-03 12:00:16 +02:00
// and store into table
$params = array (
2012-09-18 15:30:32 +02:00
'conditions' => array ( 'Event.id' => $relatedAttribute [ 'Attribute' ][ 'event_id' ]),
'recursive' => 0 ,
2012-11-28 10:55:23 +01:00
'fields' => array ( 'Event.date' , 'Event.org' , 'Event.private' , 'Event.cluster' )
2012-08-03 12:00:16 +02:00
);
2012-09-19 11:05:10 +02:00
$eventDate = $this -> Event -> find ( 'first' , $params );
2012-11-14 11:28:42 +01:00
2012-11-28 10:55:23 +01:00
// event preveal over atribute
$isPrivate = $eventDate [ 'Event' ][ 'private' ] ? $eventDate [ 'Event' ][ 'private' ] : $relatedAttribute [ 'Attribute' ][ 'private' ];
$isCluster = $eventDate [ 'Event' ][ 'cluster' ] ? $eventDate [ 'Event' ][ 'cluster' ] : $relatedAttribute [ 'Attribute' ][ 'cluster' ];
// needed seek original Org
$params = array (
'conditions' => array ( 'Event.id' => $attribute [ 'event_id' ]),
'recursive' => 0 ,
'fields' => array ( 'Event.org' , 'Event.private' , 'Event.cluster' )
);
$eventOrg = $this -> Event -> find ( 'first' , $params );
$origPrivate = isset ( $attribute [ 'private' ]) ? $attribute [ 'private' ] : false ;
$origPrivate = $eventOrg [ 'Event' ][ 'private' ] ? $eventOrg [ 'Event' ][ 'private' ] : $origPrivate ;
2012-11-26 15:34:54 +01:00
2012-08-03 12:00:16 +02:00
$this -> Correlation -> create ();
$this -> Correlation -> save ( array (
'Correlation' => array (
2012-11-28 10:55:23 +01:00
'1_event_id' => $attribute [ 'event_id' ], '1_attribute_id' => $attribute [ 'id' ], '1_private' => $origPrivate ,
2012-11-26 15:34:54 +01:00
//'1_org' => $eventOrg['Event']['org'], // TODO newest
2012-09-18 15:30:32 +02:00
'event_id' => $relatedAttribute [ 'Attribute' ][ 'event_id' ], 'attribute_id' => $relatedAttribute [ 'Attribute' ][ 'id' ],
2012-10-17 14:45:26 +02:00
'org' => $eventDate [ 'Event' ][ 'org' ],
2012-11-28 10:55:23 +01:00
'private' => $isPrivate ,
'cluster' => $isCluster ,
2012-09-19 11:05:10 +02:00
'date' => $eventDate [ 'Event' ][ 'date' ]))
2012-08-03 12:00:16 +02:00
);
2012-11-15 15:53:07 +01:00
}
}
}
public function setRelatedAttributes ( $attribute , $fields = array ()) {
$this -> setInitialRelatedAttributes ( $attribute , $fields );
$this -> Event = ClassRegistry :: init ( 'Event' );
$relatedAttributes = $this -> getRelatedAttributes ( $attribute , $fields );
if ( $relatedAttributes ) {
$this -> Correlation = ClassRegistry :: init ( 'Correlation' );
foreach ( $relatedAttributes as $relatedAttribute ) {
2012-11-14 11:28:42 +01:00
// and vise versa
$params = array (
'conditions' => array ( 'Event.id' => $attribute [ 'event_id' ]),
'recursive' => 0 ,
2012-11-28 10:55:23 +01:00
'fields' => array ( 'Event.date' , 'Event.org' , 'Event.private' , 'Event.cluster' )
2012-11-14 11:28:42 +01:00
);
$eventDate = $this -> Event -> find ( 'first' , $params );
2012-11-28 10:55:23 +01:00
// event preveal over atribute
$origPrivate = isset ( $attribute [ 'private' ]) ? $attribute [ 'private' ] : false ;
$origPrivate = $eventDate [ 'Event' ][ 'private' ] ? $eventDate [ 'Event' ][ 'private' ] : $origPrivate ;
$origCluster = isset ( $attribute [ 'cluster' ]) ? $attribute [ 'cluster' ] : false ;
$origCluster = $eventDate [ 'Event' ][ 'cluster' ] ? $eventDate [ 'Event' ][ 'cluster' ] : $origCluster ;
// event preveal over atribute
$params = array (
'conditions' => array ( 'Event.id' => $relatedAttribute [ 'Attribute' ][ 'event_id' ]),
'recursive' => 0 ,
'fields' => array ( 'Event.date' , 'Event.org' , 'Event.private' , 'Event.cluster' )
);
$isEvent = $this -> Event -> find ( 'first' , $params );
$isPrivate = $isEvent [ 'Event' ][ 'private' ] ? $isEvent [ 'Event' ][ 'private' ] : $relatedAttribute [ 'Attribute' ][ 'private' ];
$isCluster = $isEvent [ 'Event' ][ 'cluster' ] ? $isEvent [ 'Event' ][ 'cluster' ] : $relatedAttribute [ 'Attribute' ][ 'cluster' ];
2012-11-14 11:28:42 +01:00
$this -> Correlation -> create ();
$this -> Correlation -> save ( array (
'Correlation' => array (
2012-11-28 10:55:23 +01:00
'1_event_id' => $relatedAttribute [ 'Attribute' ][ 'event_id' ], '1_attribute_id' => $relatedAttribute [ 'Attribute' ][ 'id' ], '1_private' => $isPrivate ,
2012-11-26 15:34:54 +01:00
//'1_org' => $relatedAttribute['Event']['org'], // TODO newest
2012-11-14 11:28:42 +01:00
'event_id' => $attribute [ 'event_id' ], 'attribute_id' => $attribute [ 'id' ],
'org' => $eventDate [ 'Event' ][ 'org' ],
2012-11-28 10:55:23 +01:00
'private' => $origPrivate ,
'cluster' => $origCluster ,
2012-11-14 11:28:42 +01:00
'date' => $eventDate [ 'Event' ][ 'date' ]))
);
2012-08-03 12:00:16 +02:00
}
}
}
2012-05-22 13:58:37 +02:00
2012-09-18 15:30:32 +02:00
/**
* Deletes the attribute from another Server
* TODO move this to a component
*
* @ return bool true if success , error message if failed
*/
public function deleteAttributeFromServer ( $attribute , $server , $HttpSocket = null ) {
2012-08-21 16:55:57 +02:00
// TODO private and delete
2012-09-18 15:30:32 +02:00
if ( true == $attribute [ 'Attribute' ][ 'private' ]) { // never upload private attributes
return " Attribute is private and non exportable " ;
}
$url = $server [ 'Server' ][ 'url' ];
$authkey = $server [ 'Server' ][ 'authkey' ];
if ( null == $HttpSocket ) {
App :: uses ( 'HttpSocket' , 'Network/Http' );
$HttpSocket = new HttpSocket ();
}
$request = array (
'header' => array (
'Authorization' => $authkey ,
'Accept' => 'application/xml' ,
'Content-Type' => 'application/xml' ,
//'Connection' => 'keep-alive' // LATER followup cakephp ticket 2854 about this problem http://cakephp.lighthouseapp.com/projects/42648-cakephp/tickets/2854
)
);
$uri = $url . '/attributes/0?uuid=' . $attribute [ 'Attribute' ][ 'uuid' ];
// LATER validate HTTPS SSL certificate
$this -> Dns = ClassRegistry :: init ( 'Dns' );
if ( $this -> Dns -> testipaddress ( parse_url ( $uri , PHP_URL_HOST ))) {
// TODO NETWORK for now do not know how to catch the following..
// TODO NETWORK No route to host
$response = $HttpSocket -> delete ( $uri , array (), $request );
// TODO REST, DELETE, no responce needed
}
2012-08-21 16:55:57 +02:00
}
2012-05-22 13:58:37 +02:00
2012-11-14 16:14:04 +01:00
public function checkComposites () {
$compositeTypes = $this -> getCompositeTypes ();
$fails = array ();
$attributes = $this -> find ( 'all' , array ( 'recursive' => 0 ));
foreach ( $attributes as $attribute ) {
if (( in_array ( $attribute [ 'Attribute' ][ 'type' ], $compositeTypes )) && ( ! strlen ( $attribute [ 'Attribute' ][ 'value1' ]) || ! strlen ( $attribute [ 'Attribute' ][ 'value2' ]))) {
$fails [] = $attribute [ 'Attribute' ][ 'event_id' ] . ':' . $attribute [ 'Attribute' ][ 'id' ];
}
}
return $fails ;
}
2012-03-15 15:06:45 +01:00
}