MISP/app/Model/Event.php

722 lines
27 KiB
PHP
Raw Normal View History

2013-05-22 12:49:40 +02:00
<?php
App::uses('AppModel', 'Model');
App::import('Controller', 'Attributes');
/**
* Event Model
*
* @property User $User
* @property Attribute $Attribute
*/
class Event extends AppModel {
public $actsAs = array(
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'full'),
'Trim',
'Containable',
);
/**
* Display field
*
* @var string
*/
public $displayField = 'id';
public $virtualFields = array();
/**
* Description field
*
* @var array
*/
public $fieldDescriptions = array(
'risk' => array('desc' => 'Risk levels: *low* means mass-malware, *medium* means APT malware, *high* means sophisticated APT malware or 0-day attack', 'formdesc' => 'Risk levels:<br/>low: mass-malware<br/>medium: APT malware<br/>high: sophisticated APT malware or 0-day attack'),
'classification' => array('desc' => 'Set the Traffic Light Protocol classification. <ol><li><em>TLP:AMBER</em>- Share only within the organization on a need-to-know basis</li><li><em>TLP:GREEN:NeedToKnow</em>- Share within your constituency on the need-to-know basis.</li><li><em>TLP:GREEN</em>- Share within your constituency.</li></ol>'),
'submittedgfi' => array('desc' => 'GFI sandbox: export upload', 'formdesc' => 'GFI sandbox:<br/>export upload'),
2013-06-01 11:05:15 +02:00
'submittedioc' => array('desc' => '', 'formdesc' => ''),
'analysis' => array('desc' => 'Analysis Levels: *Initial* means the event has just been created, *Ongoing* means that the event is being populated, *Complete* means that the event\'s creation is complete', 'formdesc' => 'Analysis levels:<br />Initial: event has been started<br />Ongoing: event population is in progress<br />Complete: event creation has finished'),
'distribution' => array('desc' => 'Describes who will have access to the event.')
2013-05-22 12:49:40 +02:00
);
public $riskDescriptions = array(
'Undefined' => array('desc' => '*undefined* no risk', 'formdesc' => 'No risk'),
'Low' => array('desc' => '*low* means mass-malware', 'formdesc' => 'Mass-malware'),
'Medium' => array('desc' => '*medium* means APT malware', 'formdesc' => 'APT malware'),
'High' => array('desc' => '*high* means sophisticated APT malware or 0-day attack', 'formdesc' => 'Sophisticated APT malware or 0-day attack')
);
public $analysisDescriptions = array(
0 => array('desc' => '*Initial* means the event has just been created', 'formdesc' => 'Creation started'),
1 => array('desc' => '*Ongoing* means that the event is being populated', 'formdesc' => 'Creation ongoing'),
2 => array('desc' => '*Complete* means that the event\'s creation is complete', 'formdesc' => 'Creation complete')
);
public $distributionDescriptions = array(
2013-06-10 20:34:05 +02:00
0 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "This setting will only allow members of your organisation on this server to see it."),
1 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "Users that are part of your MISP community will be able to see the event. This includes your own organisation, organisations on this MISP server and organisations running MISP servers that synchronise with this server. Any other organisations connected to such linked servers will be restricted from seeing the event. Use this option if you are on the central hub of this community."), // former Community
2 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "Users that are part of your MISP community will be able to see the event. This includes all organisations on this MISP server, all organisations on MISP servers synchronising with this server and the hosting organisations of servers that connect to those afore mentioned servers (so basically any server that is 2 hops away from this one). Any other organisations connected to linked servers that are 2 hops away from this will be restricted from seeing the event. Use this option if this server isn't the central MISP hub of the community but is connected to it."),
3 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "This will share the event with all MISP communities, allowing the event to be freely propagated from one server to the next."),
2013-05-22 12:49:40 +02:00
);
public $analysisLevels = array(
0 => 'Initial', 1 => 'Ongoing', 2 => 'Completed'
);
public $distributionLevels = array(
0 => 'Your organisation only', 1 => 'This community only', 2 => 'Connected communities', 3 => 'All communities'
);
2013-05-22 12:49:40 +02:00
/**
* Validation rules
*
* @var array
*/
public $validate = array(
'org' => array(
'notempty' => array(
'rule' => array('notempty'),
//'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
),
),
'orgc' => array(
'notempty' => array(
'rule' => array('notempty'),
//'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
),
),
'date' => array(
'date' => array(
'rule' => array('date'),
//'message' => 'Your custom message here',
//'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'risk' => array(
'rule' => array('inList', array('Undefined', 'Low','Medium','High')),
'message' => 'Options : Undefined, Low, Medium, High',
//'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'distribution' => array(
2013-06-24 15:12:30 +02:00
'rule' => array('inList', array('0', '1', '2', '3')),
'message' => 'Options : Your organisation only, This community only, Connected communities, All communities',
//'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
2013-05-22 12:49:40 +02:00
'analysis' => array(
'rule' => array('inList', array('0', '1', '2')),
'message' => 'Options : 0, 1, 2',
//'allowEmpty' => false,
'required' => true,
//'last' => false, // Stop validation after this rule
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
'info' => array(
'notempty' => array(
'rule' => array('notempty'),
//'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
),
),
'user_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
),
),
'user_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
),
),
'published' => 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
),
),
//'classification' => array(
// 'rule' => array('inList', array('TLP:AMBER', 'TLP:GREEN:NeedToKnow', 'TLP:GREEN')),
// //'message' => 'Your custom message here',
// //'allowEmpty' => false,
// 'required' => true,
// //'last' => false, // Stop validation after this rule
// //'on' => 'create', // Limit validation to 'create' or 'update' operations
//),
);
public function __construct($id = false, $table = null, $ds = null) {
parent::__construct($id, $table, $ds);
//$this->virtualFields = Set::merge($this->virtualFields, array(
// 'distribution' => 'IF (Event.private=true AND Event.cluster=false, "Your organization only", IF (Event.private=true AND Event.cluster=true, "This server-only", IF (Event.private=false AND Event.cluster=true, "This Community-only", IF (Event.communitie=true, "Connected communities" , "All communities"))))',
// ));
2013-05-22 12:49:40 +02:00
}
//The Associations below have been created with all possible keys, those that are not needed can be removed
/**
* belongsTo associations
*
* @var array
*/
public $belongsTo = array(
//'Org' => array(
// 'className' => 'Org',
// 'foreignKey' => 'org',
// 'conditions' => '',
// 'fields' => '',
// 'order' => ''
//)
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
'fields' => '',
'order' => ''
)
);
/**
* hasMany associations
*
* @var array
*
* @throws InternalErrorException // TODO Exception
*/
public $hasMany = array(
'Attribute' => array(
'className' => 'Attribute',
'foreignKey' => 'event_id',
'dependent' => true, // cascade deletes
'conditions' => '',
'fields' => '',
'order' => array('Attribute.category ASC', 'Attribute.type ASC'),
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
),
'ShadowAttribute' => array(
'className' => 'ShadowAttribute',
'foreignKey' => 'event_id',
'dependent' => true, // cascade deletes
'conditions' => '',
'fields' => '',
'order' => array('ShadowAttribute.old_id DESC', 'ShadowAttribute.old_id DESC'),
'limit' => '',
'offset' => '',
'exclusive' => '',
'finderQuery' => '',
'counterQuery' => ''
2013-05-22 12:49:40 +02:00
)
);
public function beforeDelete($cascade = true) {
// delete event from the disk
$this->read(); // first read the event from the db
// 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['Event']['id'];
App::uses('Folder', 'Utility');
$file = new Folder ($filepath);
if (is_dir($filepath)) {
if (!$this->destroyDir($filepath)) {
throw new InternalErrorException('Delete of event file directory failed. Please report to administrator.');
}
}
}
public function destroyDir($dir) {
if (!is_dir($dir) || is_link($dir)) return unlink($dir);
foreach (scandir($dir) as $file) {
if ($file == '.' || $file == '..') continue;
if (!$this->destroyDir($dir . DS . $file)) {
chmod($dir . DS . $file, 0777);
if (!$this->destroyDir($dir . DS . $file)) return false;
};
}
return rmdir($dir);
}
public function beforeValidate($options = array()) {
parent::beforeValidate();
// analysis - setting correct vars
// TODO refactor analysis into an Enum (in the database)
if (isset($this->data['Event']['analysis'])) {
switch($this->data['Event']['analysis']){
case 'Initial':
$this->data['Event']['analysis'] = 0;
break;
case 'Ongoing':
$this->data['Event']['analysis'] = 1;
break;
case 'Completed':
$this->data['Event']['analysis'] = 2;
break;
}
}
// generate UUID if it doesn't exist
if (empty($this->data['Event']['uuid'])) {
$this->data['Event']['uuid'] = String::uuid();
}
// generate timestamp if it doesn't exist
if (empty($this->data['Event']['timestamp'])) {
$date = new DateTime();
$this->data['Event']['timestamp'] = $date->getTimestamp();
}
2013-05-22 12:49:40 +02:00
}
public function isOwnedByOrg($eventid, $org) {
return $this->field('id', array('id' => $eventid, 'org' => $org)) === $eventid;
}
public function getRelatedEvents($me, $isSiteAdmin = false, $eventId = null) {
if ($eventId == null) $eventId = $this->data['Event']['id'];
2013-05-22 12:49:40 +02:00
$this->Correlation = ClassRegistry::init('Correlation');
// search the correlation table for the event ids of the related events
if (!$isSiteAdmin) {
2013-05-22 12:49:40 +02:00
$conditionsCorrelation = array('AND' =>
array('Correlation.1_event_id' => $eventId),
2013-05-22 12:49:40 +02:00
array("OR" => array(
'Correlation.org' => $me['org'],
'Correlation.private' => 0),
));
} else {
$conditionsCorrelation = array('Correlation.1_event_id' => $eventId);
2013-05-22 12:49:40 +02:00
}
$correlations = $this->Correlation->find('all',array(
'fields' => 'Correlation.event_id',
'conditions' => $conditionsCorrelation,
'recursive' => 0,
'order' => array('Correlation.event_id DESC')));
$relatedEventIds = array();
foreach ($correlations as $correlation) {
$relatedEventIds[] = $correlation['Correlation']['event_id'];
}
2013-06-11 00:44:04 +02:00
$relatedEventIds = array_unique($relatedEventIds);
2013-05-22 12:49:40 +02:00
// now look up the event data for these attributes
$conditions = array("Event.id" => $relatedEventIds);
$relatedEvents = $this->find('all',
array('conditions' => $conditions,
'recursive' => 0,
'order' => 'Event.date DESC',
'fields' => 'Event.*'
)
);
return $relatedEvents;
}
public function getRelatedAttributes($me, $isSiteAdmin = false, $id = null) {
if ($id == null) $id = $this->data['Event']['id'];
2013-05-22 12:49:40 +02:00
$this->Correlation = ClassRegistry::init('Correlation');
// search the correlation table for the event ids of the related attributes
if (!$isSiteAdmin) {
2013-05-22 12:49:40 +02:00
$conditionsCorrelation = array('AND' =>
array('Correlation.1_event_id' => $id),
2013-05-22 12:49:40 +02:00
array("OR" => array(
'Correlation.org' => $me['org'],
'Correlation.private' => 0),
));
} else {
$conditionsCorrelation = array('Correlation.1_event_id' => $id);
2013-05-22 12:49:40 +02:00
}
$correlations = $this->Correlation->find('all',array(
'fields' => 'Correlation.*',
'conditions' => $conditionsCorrelation,
'recursive' => 0,
'order' => array('Correlation.event_id DESC')));
$relatedAttributes = array();
foreach($correlations as $correlation) {
$current = array(
2013-05-22 12:49:40 +02:00
'id' => $correlation['Correlation']['event_id'],
'org' => $correlation['Correlation']['org'],
'info' => $correlation['Correlation']['info']
);
if (empty($relatedAttributes[$correlation['Correlation']['1_attribute_id']]) || !in_array($current, $relatedAttributes[$correlation['Correlation']['1_attribute_id']])) {
$relatedAttributes[$correlation['Correlation']['1_attribute_id']][] = $current;
}
2013-05-22 12:49:40 +02:00
}
return $relatedAttributes;
}
/**
* Clean up an Event Array that was received by an XML request.
* The structure needs to be changed a little bit to be compatible with what CakePHP expects
*
* This function receives the reference of the variable, so no return is required as it directly
* modifies the original data.
*
* @param &$data The reference to the variable
*
2013-05-28 11:15:21 +02:00
* @throws InternalErrorException
2013-05-22 12:49:40 +02:00
*/
public function cleanupEventArrayFromXML(&$data) {
// Workaround for different structure in XML/array than what CakePHP expects
if (isset($data['Event']['Attribute']) && is_array($data['Event']['Attribute']) && count($data['Event']['Attribute'])) {
if (is_numeric(implode(array_keys($data['Event']['Attribute']), ''))) {
// normal array of multiple Attributes
$data['Attribute'] = $data['Event']['Attribute'];
} else {
// single attribute
$data['Attribute'][0] = $data['Event']['Attribute'];
}
}
unset($data['Event']['Attribute']);
return $data;
}
public function uploadEventToServer($event, $server, $HttpSocket = null) {
$updated = null;
$newLocation = $newTextBody = '';
$result = $this->restfullEventToServer($event, $server, null, $newLocation, $newTextBody, $HttpSocket);
if ($result === 403) {
2013-08-12 17:23:32 +02:00
return 'The distribution level of this event blocks it from being pushed.';
2013-05-22 12:49:40 +02:00
}
if (strlen($newLocation) || $result) { // HTTP/1.1 200 OK or 302 Found and Location: http://<newLocation>
if (strlen($newLocation)) { // HTTP/1.1 302 Found and Location: http://<newLocation>
//$updated = true;
$result = $this->restfullEventToServer($event, $server, $newLocation, $newLocation, $newTextBody, $HttpSocket);
2013-08-12 17:23:32 +02:00
if ($result === 405) {
return 'You do not have permission to edit this event or the event is up to date.';
}
2013-05-22 12:49:40 +02:00
}
try { // TODO Xml::build() does not throw the XmlException
$xml = Xml::build($newTextBody);
} catch (XmlException $e) {
//throw new InternalErrorException();
return false;
}
// get the remote event_id
foreach ($xml as $xmlEvent) {
foreach ($xmlEvent as $key => $value) {
if ($key == 'id') {
$remoteId = (int)$value;
break;
}
}
}
// get the new attribute uuids in an array
$newerUuids = array();
foreach ($event['Attribute'] as $attribute) {
$newerUuids[$attribute['id']] = $attribute['uuid'];
$attribute['event_id'] = $remoteId;
}
// get the already existing attributes and delete the ones that are not there
foreach ($xml->Event->Attribute as $attribute) {
foreach ($attribute as $key => $value) {
if ($key == 'uuid') {
if (!in_array((string)$value, $newerUuids)) {
$anAttr = ClassRegistry::init('Attribute');
$anAttr->deleteAttributeFromServer((string)$value, $server, $HttpSocket);
}
}
}
}
}
2013-08-12 17:23:32 +02:00
return 'Success';
2013-05-22 12:49:40 +02:00
}
/**
* Uploads the event and the associated Attributes to another Server
* TODO move this to a component
*
* @return bool true if success, false or error message if failed
*/
public function restfullEventToServer($event, $server, $urlPath, &$newLocation, &$newTextBody, $HttpSocket = null) {
if ($event['Event']['distribution'] < 2) { // never upload private events
2013-07-17 14:27:51 +02:00
return 403; //"Event is private and non exportable";
2013-05-22 12:49:40 +02:00
}
$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 = isset($urlPath) ? $urlPath : $url . '/events';
// LATER try to do this using a separate EventsController and renderAs() function
$xmlArray = array();
// rearrange things to be compatible with the Xml::fromArray()
$event['Event']['Attribute'] = $event['Attribute'];
unset($event['Attribute']);
// cleanup the array from things we do not want to expose
//unset($event['Event']['org']);
// remove value1 and value2 from the output
foreach ($event['Event']['Attribute'] as $key => &$attribute) {
// do not keep attributes that are private, nor cluster
if ($attribute['distribution'] < 2) {
2013-05-22 12:49:40 +02:00
unset($event['Event']['Attribute'][$key]);
continue; // stop processing this
}
// Distribution, correct Connected Community to Community in Attribute
if ($attribute['distribution'] == 2) {
$attribute['distribution'] = 1;
2013-05-22 12:49:40 +02:00
}
// remove value1 and value2 from the output
unset($attribute['value1']);
unset($attribute['value2']);
// also add the encoded attachment
if ($this->Attribute->typeIsAttachment($attribute['type'])) {
$encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
$attribute['data'] = $encodedFile;
}
// Passing the attribute ID together with the attribute could cause the deletion of attributes after a publish/push
// Basically, if the attribute count differed between two instances, and the instance with the lower attribute
// count pushed, the old attributes with the same ID got overwritten. Unsetting the ID before pushing it
// solves the issue and a new attribute is always created.
unset($attribute['id']);
}
// Distribution, correct All to Community in Event
if ($event['Event']['distribution'] == 2) {
$event['Event']['distribution'] = 1;
2013-05-22 12:49:40 +02:00
}
// display the XML to the user
$xmlArray['Event'][] = $event['Event'];
$xmlObject = Xml::fromArray($xmlArray, array('format' => 'tags'));
$eventsXml = $xmlObject->asXML();
// do a REST POST request with the server
$data = $eventsXml;
// 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->post($uri, $data, $request);
switch ($response->code) {
case '200': // 200 (OK) + entity-action-result
if ($response->isOk()) {
$newTextBody = $response->body();
$newLocation = null;
return true;
//return isset($urlPath) ? $response->body() : true;
} else {
try {
// parse the XML response and keep the reason why it failed
$xmlArray = Xml::toArray(Xml::build($response->body));
} catch (XmlException $e) {
return true; // TODO should be false
}
if (strpos($xmlArray['response']['name'],"Event already exists")) { // strpos, so i can piggyback some value if needed.
return true;
} else {
return $xmlArray['response']['name'];
}
}
break;
case '302': // Found
$newLocation = $response->headers['Location'];
$newTextBody = $response->body();
return true;
//return isset($urlPath) ? $response->body() : $response->headers['Location'];
break;
2013-08-12 17:23:32 +02:00
case '404': // Not Found
$newLocation = $response->headers['Location'];
$newTextBody = $response->body();
return 404;
break;
case '405':
return 405;
break;
case '403': // Not authorised
2013-05-22 12:49:40 +02:00
return 403;
2013-08-12 17:23:32 +02:00
break;
2013-05-22 12:49:40 +02:00
}
}
}
/**
* Deletes the event and the associated Attributes from another Server
* TODO move this to a component
*
* @return bool true if success, error message if failed
*/
public function deleteEventFromServer($uuid, $server, $HttpSocket=null) {
// TODO private and delete(?)
$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 . '/events/0?uuid=' . $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, some responce needed
}
}
/**
* Download a specific event from a Server
* TODO move this to a component
* @return array|NULL
*/
public function downloadEventFromServer($eventId, $server, $HttpSocket=null) {
$url = $server['Server']['url'];
$authkey = $server['Server']['authkey'];
if (null == $HttpSocket) {
App::uses('HttpSocket', 'Network/Http');
2013-06-24 15:12:30 +02:00
//$HttpSocket = new HttpSocket(array(
// 'ssl_verify_peer' => false
// ));
2013-05-22 12:49:40 +02:00
$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 . '/events/' . $eventId;
$response = $HttpSocket->get($uri, $data = '', $request);
if ($response->isOk()) {
$xmlArray = Xml::toArray(Xml::build($response->body));
return $xmlArray['response'];
} else {
// TODO parse the XML response and keep the reason why it failed
return null;
}
}
/**
* Get an array of event_ids that are present on the remote server
* TODO move this to a component
* @return array of event_ids
*/
public function getEventIdsFromServer($server, $HttpSocket=null) {
$url = $server['Server']['url'];
$authkey = $server['Server']['authkey'];
if (null == $HttpSocket) {
App::uses('HttpSocket', 'Network/Http');
2013-06-24 15:12:30 +02:00
//$HttpSocket = new HttpSocket(array(
// 'ssl_verify_peer' => false
// ));
2013-05-22 12:49:40 +02:00
$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 . '/events/index/sort:id/direction:desc/limit:999'; // LATER verify if events are missing because we only selected the last 999
try {
2013-05-22 12:49:40 +02:00
$response = $HttpSocket->get($uri, $data = '', $request);
if ($response->isOk()) {
//debug($response->body);
$xml = Xml::build($response->body);
$eventArray = Xml::toArray($xml);
// correct $eventArray if just one event
if (is_array($eventArray['response']['Event']) && isset($eventArray['response']['Event']['id'])) {
$tmp = $eventArray['response']['Event'];
unset($eventArray['response']['Event']);
$eventArray['response']['Event'][0] = $tmp;
}
$eventIds = array();
// different actions if it's only 1 event or more
// only one event.
if (isset($eventArray['response']['Event']['id'])) {
$eventIds[] = $eventArray['response']['Event']['id'];
} else {
// multiple events, iterate over the array
foreach ($eventArray['response']['Event'] as &$event) {
if (1 != $event['published']) {
continue; // do not keep non-published events
}
$eventIds[] = $event['id'];
}
}
return $eventIds;
}
if ($response->code == '403') {
return 403;
}
} catch (SocketException $e){
// FIXME refactor this with clean try catch over all http functions
return $e->getMessage();
2013-05-22 12:49:40 +02:00
}
// error, so return null
return null;
}
}