Further work on the sharing groups:

- changes to the data model
- correlation engine updated
pull/762/head
iglocska 2015-04-09 17:27:34 +02:00
parent 9ccf69f35a
commit 5abd8dfead
6 changed files with 241 additions and 79 deletions

View File

@ -28,6 +28,10 @@ class EventsController extends AppController {
'order' => array(
'Event.timestamp' => 'DESC'
),
'contain' => array(
'Org' => array('fields' => array('id', 'name')),
'Orgc' => array('fields' => array('id', 'name'))
)
);
public $helpers = array('Js' => array('Jquery'));
@ -910,6 +914,8 @@ class EventsController extends AppController {
if (!$this->userRole['perm_add']) {
throw new MethodNotAllowedException('You don\'t have permissions to create events');
}
$this->loadModel('SharingGroup');
$sgs = $this->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name');
if ($this->request->is('post')) {
if ($this->_isRest()) {
@ -930,6 +936,13 @@ class EventsController extends AppController {
is_uploaded_file($this->data['Event']['submittedgfi']['tmp_name'])) {
$this->Session->setFlash(__('You may only upload GFI Sandbox zip files.'));
} else {
// If the distribution is set to sharing group, check if the id provided is really visible to the user, if not throw an error.
if ($this->request->data['Event']['distribution'] == 4) {
if (!isset($sgs[$this->request->data['Event']['sharing_group_id']])) throw new MethodNotAllowedException('Invalid Sharing Group or not authorised.');
} else {
// If the distribution is set to something "traditional", set the SG id to 0.
$this->request->data['Event']['sharing_group_id'] = 0;
}
if ($this->_isRest()) $this->request->data = $this->Event->updateXMLArray($this->request->data, false);
$add = $this->Event->_add($this->request->data, $this->_isRest(), $this->Auth->user(), '');
if ($add && !is_numeric($add)) {
@ -985,6 +998,9 @@ class EventsController extends AppController {
// combobox for analysis
$analysiss = $this->Event->validate['analysis']['rule'][1];
$analysiss = $this->_arrayToValuesIndexArray($analysiss);
$this->loadModel('SharingGroup');
$sgs = $this->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name');
$this->set('sharingGroups', $sgs);
$this->set('analysiss',$analysiss);
// tooltip for analysis
$this->set('analysisDescriptions', $this->Event->analysisDescriptions);
@ -1777,15 +1793,12 @@ class EventsController extends AppController {
// Grab an event or a list of events for the event view or any of the XML exports. The returned object includes an array of events (or an array that only includes a single event if an ID was given)
// Included with the event are the attached attributes, shadow attributes, related events, related attribute information for the event view and the creating user's email address where appropriate
private function __fetchEvent($eventid = false, $idList = false, $orgFromFetch = false, $isSiteAdmin = false, $tags = false, $from=false, $to=false) {
private function __fetchEvent($eventid = false, $idList = false, $user = false, $tags = false, $from=false, $to=false) {
// if we come from automation, we may not be logged in - instead we used an auth key in the URL.
if (!empty($orgFromFetch)) {
$org = $orgFromFetch;
} else {
$org = $this->_checkOrg();
$isSiteAdmin = $this->_isSiteAdmin();
if (empty($user)) {
$user = $this->Auth->user();
}
$results = $this->Event->fetchEvent($eventid, $idList, $org, $isSiteAdmin, null, $tags, $from, $to);
$results = $this->Event->fetchEvent($eventid, $idList, $user, null, $tags, $from, $to);
return $results;
}

View File

@ -420,7 +420,6 @@ class Attribute extends AppModel {
// update correlation..
$this->__beforeDeleteCorrelation($this->data['Attribute']['id']);
}
public function beforeValidate($options = array()) {
@ -979,8 +978,10 @@ class Attribute extends AppModel {
'AND' => array(
'Attribute.type !=' => $this->nonCorrelatingTypes,
)),
'recursive' => 0,
//'contain' => 'Event',
'recursive' => -1,
'contain' => array(
'Event'
),
//'fields' => '', // we want to have the Attribute AND Event, so do not filter here
);
// search for the related attributes for that "value(1|2)"
@ -997,15 +998,18 @@ class Attribute extends AppModel {
// or attributes from the same event
continue;
}
$is_private = ($attribute_right['Event']['distribution'] == 0) || ($attribute_right['Attribute']['distribution'] == 0);
// With the sharing group design, we want to save the distribution level and the sharing group ID for both the right attribute and event
$correlations[] = array(
'value' => $a[$value_name],
'1_event_id' => $attribute['Attribute']['event_id'],
'1_attribute_id' => $attribute['Attribute']['id'],
'event_id' => $attribute_right['Attribute']['event_id'],
'attribute_id' => $attribute_right['Attribute']['id'],
'org' => $attribute_right['Event']['org'],
'private' => $is_private,
'org' => $attribute_right['Event']['org_id'],
'distribution' => $attribute_right['Event']['distribution'],
'a_distribution' => $attribute_right['Attribute']['distribution'],
'sharing_group_id' => $attribute_right['Event']['sharing_group_id'],
'a_sharing_group_id' => $attribute_right['Attribute']['sharing_group_id'],
'date' => $attribute_right['Event']['date'],
'info' => $attribute_right['Event']['info'],
);

View File

@ -28,7 +28,7 @@ class Event extends AppModel {
public $virtualFields = array();
public $mispVersion = '2.3.0';
public $mispVersion = '2.4.0';
/**
* Description field
@ -62,6 +62,8 @@ class Event extends AppModel {
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."),
4 => array('desc' => 'This field determines the current distribution of the event', 'formdesc' => "This distribution of this event will be handled by the selected sharing group."),
);
public $analysisLevels = array(
@ -69,7 +71,7 @@ class Event extends AppModel {
);
public $distributionLevels = array(
0 => 'Your organisation only', 1 => 'This community only', 2 => 'Connected communities', 3 => 'All communities'
0 => 'Your organisation only', 1 => 'This community only', 2 => 'Connected communities', 3 => 'All communities', 4 => 'Sharing group'
);
public $export_types = array(
@ -131,7 +133,7 @@ class Event extends AppModel {
* @var array
*/
public $validate = array(
'org' => array(
'org_id' => array(
'notempty' => array(
'rule' => array('notempty'),
//'message' => 'Your custom message here',
@ -141,7 +143,7 @@ class Event extends AppModel {
//'on' => 'create', // Limit validation to 'create' or 'update' operations
),
),
'orgc' => array(
'orgc_id' => array(
'notempty' => array(
'rule' => array('notempty'),
//'message' => 'Your custom message here',
@ -170,14 +172,23 @@ class Event extends AppModel {
),
'distribution' => array(
'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
'not_empty_if_sg' => array(
'rule' => array('inList', array('0', '1', '2', '3', '4')),
'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
)
),
'sharing_group_id' => array(
'rule' => array('sharingGroupRequired'),
'message' => 'If the distribution is set to "Sharing Group", a sharing group has to be selected.',
//'required' => true,
//'allowEmpty' => true
),
'analysis' => array(
'rule' => array('inList', array('0', '1', '2')),
'message' => 'Options : 0, 1, 2',
@ -278,6 +289,18 @@ class Event extends AppModel {
'ThreatLevel' => array(
'className' => 'ThreatLevel',
'foreignKey' => 'threat_level_id'
),
'Org' => array(
'className' => 'Organisation',
'foreignKey' => 'org_id'
),
'Orgc' => array(
'className' => 'Organisation',
'foreignKey' => 'org_id'
),
'SharingGroup' => array(
'className' => 'SharingGroup',
'foreignKey' => 'sharing_group_id'
)
);
@ -303,20 +326,20 @@ class Event extends AppModel {
'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' => ''
'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' => ''
),
'EventTag' => array(
'className' => 'EventTag',
'className' => 'EventTag',
)
);
@ -384,17 +407,54 @@ class Event extends AppModel {
return $this->field('id', array('id' => $eventid, 'org' => $org)) === $eventid;
}
public function getRelatedEvents($me, $isSiteAdmin = false, $eventId = null) {
public function getRelatedEvents($user, $eventId = null, $sgids) {
if ($eventId == null) $eventId = $this->data['Event']['id'];
$this->Correlation = ClassRegistry::init('Correlation');
// search the correlation table for the event ids of the related events
if (!$isSiteAdmin) {
$conditionsCorrelation = array('AND' =>
array('Correlation.1_event_id' => $eventId),
array("OR" => array(
'Correlation.org' => $me['org'],
'Correlation.private' => 0),
));
// Rules:
// 1. Event is owned by the user (org_id matches)
// 2. User is allowed to see both the event and the org:
// a. Event:
// i. Event has a distribution between 1-3 (community only, connected communities, all orgs)
// ii. Event has a sharing group that the user is accessible to view
// b. Attribute:
// i. Attribute has a distribution of 5 (inheritance of the event, for this the event check has to pass anyway)
// ii. Atttibute has a distribution between 1-3 (community only, connected communities, all orgs)
// iii. Attribute has a sharing group that the user is accessible to view
if (!$user['Role']['perm_site_admin']) {
$conditionsCorrelation = array(
'AND' => array(
'Correlation.1_event_id' => $eventId,
array(
'OR' => array(
'Correlation.org_id' => $user['Org']['id'],
'AND' => array(
'OR' => array(
'AND' => array(
'Correlation.distribution >' => 0,
'Correlation.distribution <' => 4,
),
'AND' => array(
'Correlation.distribution' => 4,
'Correlation.sharing_group_id' => $sgids
),
),
'OR' => array(
'Correlation.a_distribution' => 5,
'AND' => array(
'Correlation.a_distribution >' => 0,
'Correlation.a_distribution <' => 4,
),
'AND' => array(
'Correlation.a_distribution' => 4,
'Correlation.a_sharing_group_id' => $sgids
),
),
),
),
),
),
);
} else {
$conditionsCorrelation = array('Correlation.1_event_id' => $eventId);
}
@ -421,17 +481,44 @@ class Event extends AppModel {
return $relatedEvents;
}
public function getRelatedAttributes($me, $isSiteAdmin = false, $id = null) {
public function getRelatedAttributes($user, $id = null, $sgids) {
if ($id == null) $id = $this->data['Event']['id'];
$this->Correlation = ClassRegistry::init('Correlation');
// search the correlation table for the event ids of the related attributes
if (!$isSiteAdmin) {
$conditionsCorrelation = array('AND' =>
array('Correlation.1_event_id' => $id),
array("OR" => array(
'Correlation.org' => $me['org'],
'Correlation.private' => 0),
));
if (!$user['Role']['perm_site_admin']) {
$conditionsCorrelation = array(
'AND' => array(
'Correlation.1_event_id' => $eventId,
array(
'OR' => array(
'Correlation.org_id' => $user['Org']['id'],
'AND' => array(
'OR' => array(
'AND' => array(
'Correlation.distribution >' => 0,
'Correlation.distribution <' => 4,
),
'AND' => array(
'Correlation.distribution' => 4,
'Correlation.sharing_group_id' => $sgids
),
),
'OR' => array(
'Correlation.a_distribution' => 5,
'AND' => array(
'Correlation.a_distribution >' => 0,
'Correlation.a_distribution <' => 4,
),
'AND' => array(
'Correlation.a_distribution' => 4,
'Correlation.a_sharing_group_id' => $sgids
),
),
),
),
),
),
);
} else {
$conditionsCorrelation = array('Correlation.1_event_id' => $id);
}
@ -441,7 +528,7 @@ class Event extends AppModel {
'recursive' => 0,
'order' => array('Correlation.event_id DESC')));
$relatedAttributes = array();
foreach($correlations as $correlation) {
foreach ($correlations as $correlation) {
$current = array(
'id' => $correlation['Correlation']['event_id'],
'org' => $correlation['Correlation']['org'],
@ -828,7 +915,7 @@ class Event extends AppModel {
}
//Once the data about the user is gathered from the appropriate sources, fetchEvent is called from the controller.
public function fetchEvent($eventid = false, $idList = false, $org, $isSiteAdmin = false, $bkgrProcess = false, $tags = false, $from = false, $to = false) {
public function fetchEvent($eventid = false, $idList = false, $user, $bkgrProcess = false, $tags = false, $from = false, $to = false) {
if ($eventid) {
$this->id = $eventid;
if (!$this->exists()) {
@ -838,15 +925,19 @@ class Event extends AppModel {
} else {
$conditions = array();
}
$me['org'] = $org;
// if we come from automation, we may not be logged in - instead we used an auth key in the URL.
$isSiteAdmin = $user['Role']['perm_site_admin'];
$conditionsAttributes = array();
//restricting to non-private or same org if the user is not a site-admin.
if (!$isSiteAdmin) {
if (!$user['Role']['perm_site_admin']) {
$sgids = $this->SharingGroup->fetchAllAuthorised($user);
$conditions['AND']['OR'] = array(
'Event.distribution >' => 0,
'Event.org LIKE' => $org
'OR' => array(
'Event.distribution >' => 0,
'Event.org LIKE' => $org
),
'Event.sharing_group_id' => $sgids
);
$conditionsAttributes['OR'] = array(
'Attribute.distribution >' => 0,
@ -888,7 +979,9 @@ class Event extends AppModel {
$fields = array('Event.id', 'Event.org', 'Event.date', 'Event.threat_level_id', 'Event.info', 'Event.published', 'Event.uuid', 'Event.attribute_count', 'Event.analysis', 'Event.timestamp', 'Event.distribution', 'Event.proposal_email_lock', 'Event.orgc', 'Event.user_id', 'Event.locked', 'Event.publish_timestamp');
$fieldsAtt = array('Attribute.id', 'Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.to_ids', 'Attribute.uuid', 'Attribute.event_id', 'Attribute.distribution', 'Attribute.timestamp', 'Attribute.comment');
$fieldsShadowAtt = array('ShadowAttribute.id', 'ShadowAttribute.type', 'ShadowAttribute.category', 'ShadowAttribute.value', 'ShadowAttribute.to_ids', 'ShadowAttribute.uuid', 'ShadowAttribute.event_id', 'ShadowAttribute.old_id', 'ShadowAttribute.comment', 'ShadowAttribute.org');
$fieldsOrg = array('id', 'name');
$params = array('conditions' => $conditions,
'recursive' => 0,
'fields' => $fields,
@ -896,6 +989,8 @@ class Event extends AppModel {
'ThreatLevel' => array(
'fields' => array('ThreatLevel.name')
),
'Org' => array('fields' => $fieldsOrg),
'Orgc' => array('fields' => $fieldsOrg),
'Attribute' => array(
'fields' => $fieldsAtt,
'conditions' => $conditionsAttributes,
@ -904,16 +999,25 @@ class Event extends AppModel {
'fields' => $fieldsShadowAtt,
'conditions' => array('deleted' => 0),
),
'SharingGroup' => array(
'SharingGroupOrg' => array(
'Organisation' => array('fields' => $fieldsOrg),
),
'SharingGroupServer' => array(
'Server',
),
),
)
);
if ($isSiteAdmin) $params['contain']['User'] = array('fields' => 'email');
$results = $this->find('all', $params);
// Do some refactoring with the event
$sgsids = $this->SharingGroup->fetchAllAuthorised($user);
foreach ($results as $eventKey => &$event) {
// Let's find all the related events and attach it to the event itself
$results[$eventKey]['RelatedEvent'] = $this->getRelatedEvents($me, $isSiteAdmin, $event['Event']['id']);
$results[$eventKey]['RelatedEvent'] = $this->getRelatedEvents($user, $event['Event']['id'], $sgsids);
// Let's also find all the relations for the attributes - this won't be in the xml export though
$results[$eventKey]['RelatedAttribute'] = $this->getRelatedAttributes($me, $isSiteAdmin, $event['Event']['id']);
$results[$eventKey]['RelatedAttribute'] = $this->getRelatedAttributes($user, $event['Event']['id'], $sgsids);
foreach ($event['Attribute'] as $key => &$attribute) {
$attribute['ShadowAttribute'] = array();
// If a shadowattribute can be linked to an attribute, link it to it then remove it from the event
@ -1409,13 +1513,13 @@ class Event extends AppModel {
//if ($this->checkAction('perm_sync')) $data['Event']['org'] = Configure::read('MISP.org');
//else $data['Event']['org'] = $auth->user('org');
if ($fromPull) {
$data['Event']['org'] = $org;
$data['Event']['org_id'] = $org;
} else {
$data['Event']['org'] = $user['org'];
$data['Event']['org_id'] = $user['Organisation']['id'];
}
// set these fields if the event is freshly created and not pushed from another instance.
// Moved out of if (!$fromXML), since we might get a restful event without the orgc/timestamp set
if (!isset ($data['Event']['orgc'])) $data['Event']['orgc'] = $data['Event']['org'];
if (!isset ($data['Event']['orgc_id'])) $data['Event']['orgc_id'] = $data['Event']['org_id'];
if ($fromXml) {
// Workaround for different structure in XML/array than what CakePHP expects
$data = $this->cleanupEventArrayFromXML($data);
@ -1442,11 +1546,10 @@ class Event extends AppModel {
}
// FIXME chri: validatebut the necessity for all these fields...impact on security !
$fieldList = array(
'Event' => array('org', 'orgc', 'date', 'threat_level_id', 'analysis', 'info', 'user_id', 'published', 'uuid', 'timestamp', 'distribution', 'locked'),
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'revision', 'timestamp', 'distribution', 'comment')
'Event' => array('org_id', 'orgc_id', 'date', 'threat_level_id', 'analysis', 'info', 'user_id', 'published', 'uuid', 'timestamp', 'distribution', 'sharing_group_id', 'locked'),
'Attribute' => array('event_id', 'category', 'type', 'value', 'value1', 'value2', 'to_ids', 'uuid', 'timestamp', 'distribution', 'comment')
);
$saveResult = $this->saveAssociated($data, array('validate' => true, 'fieldList' => $fieldList,
'atomic' => true));
$saveResult = $this->saveAssociated($data, array('validate' => true, 'fieldList' => $fieldList,'atomic' => true));
// FIXME chri: check if output of $saveResult is what we expect when data not valid, see issue #104
if ($saveResult) {
if (!empty($data['Event']['published']) && 1 == $data['Event']['published']) {
@ -1458,6 +1561,7 @@ class Event extends AppModel {
}
return true;
} else {
debug($this->validationErrors);
//throw new MethodNotAllowedException("Validation ERROR: \n".var_export($this->Event->validationErrors, true));
return false;
}
@ -1904,4 +2008,11 @@ class Event extends AppModel {
}
return $fn;
}
public function sharingGroupRequired($field) {
if ($this->data[$this->alias]['distribution'] == 4) {
return (!empty($field));
}
return true;
}
}

View File

@ -57,7 +57,8 @@ class SharingGroup extends AppModel {
}
// returns a list of all sharing groups that the user is allowed to see
public function fetchAllAuthorised($user) {
// pass true to get the actual SG objects
public function fetchAllAuthorised($user, $scope = false) {
if ($user['Role']['perm_site_admin']) {
$sgs = $this->find('all', array(
'recursive' => -1,
@ -68,7 +69,23 @@ class SharingGroup extends AppModel {
} else {
$ids = array_unique(array_merge($this->SharingGroupServer->fetchAllAuthorised(), $this->SharingGroupOrg->fetchAllAuthorised($user['Organisation']['id'])));
}
return $ids;
if ($scope === 'full') {
$sgs = $this->find('all', array(
'contain' => array('SharingGroupServer' => array('Server'), 'SharingGroupOrg' => array('Organisation'), 'Organisation'),
'conditions' => array('SharingGroup.id' => $ids),
'order' => 'name ASC'
));
return $sgs;
} else if ($scope == 'name') {
$sgs = $this->find('list', array(
'recursive' => -1,
'fields' => array('id', 'name'),
'order' => 'name ASC'
));
return $sgs;
} else {
return $ids;
}
}
// returns true if the SG exists and the user is allowed to see it

View File

@ -13,9 +13,21 @@
}
echo $this->Form->input('distribution', array(
'options' => array($distributionLevels),
'div' => 'input clear',
'label' => 'Distribution',
'selected' => $initialDistribution,
));
?>
<div id="SGContainer" style="display:none;">
<?php
echo $this->Form->input('sharing_group_id', array(
'options' => array($sharingGroups),
'label' => 'Sharing Group',
'selected' => $initialDistribution,
));
?>
</div>
<?php
echo $this->Form->input('threat_level_id', array(
'div' => 'input clear'
));
@ -70,6 +82,11 @@ foreach ($analysisDescriptions as $type => $def) {
}
?>
$('#EventDistribution').change(function() {
if ($('#EventDistribution').val() == 4) $('#SGContainer').show();
else $('#SGContainer').hide();
});
$(document).ready(function() {
$("#EventAnalysis, #EventThreatLevelId, #EventDistribution").on('mouseover', function(e) {

View File

@ -99,23 +99,23 @@
}?>&nbsp;
</td>
<?php if (Configure::read('MISP.showorg') || $isAdmin): ?>
<td class="short" ondblclick="document.location.href ='/events/view/<?php echo $event['Event']['id'];?>'">
<td class="short" ondblclick="document.location.href ='/organisations/view/<?php echo $event['Orgc']['id'];?>'">
<?php
$imgRelativePath = 'orgs' . DS . h($event['Event']['orgc']) . '.png';
$imgRelativePath = 'orgs' . DS . h($event['Orgc']['name']) . '.png';
$imgAbsolutePath = APP . WEBROOT_DIR . DS . 'img' . DS . $imgRelativePath;
if (file_exists($imgAbsolutePath)) echo $this->Html->image('orgs/' . h($event['Event']['orgc']) . '.png', array('alt' => h($event['Event']['orgc']), 'title' => h($event['Event']['orgc']), 'style' => 'width:24px; height:24px'));
else echo $this->Html->tag('span', h($event['Event']['orgc']), array('class' => 'welcome', 'style' => 'float:left;'));
if (file_exists($imgAbsolutePath)) echo $this->Html->image('orgs/' . h($event['Orgc']['name']) . '.png', array('alt' => h($event['Orgc']['name']), 'title' => h($event['Orgc']['name']), 'style' => 'width:24px; height:24px'));
else echo $this->Html->tag('span', h($event['Orgc']['name']), array('class' => 'welcome', 'style' => 'float:left;'));
?>
&nbsp;
</td>
<?php endif;?>
<?php if ($isSiteAdmin || (Configure::read('MISP.showorgalternate') && Configure::read('MISP.showorg'))): ?>
<td class="short" ondblclick="document.location.href ='/events/view/<?php echo $event['Event']['id'];?>'">
<td class="short" ondblclick="document.location.href ='/organisations/view/<?php echo $event['Org']['id'];?>'">
<?php
$imgRelativePath = 'orgs' . DS . h($event['Event']['org']) . '.png';
$imgRelativePath = 'orgs' . DS . h($event['Org']['name']) . '.png';
$imgAbsolutePath = APP . WEBROOT_DIR . DS . 'img' . DS . $imgRelativePath;
if (file_exists($imgAbsolutePath)) echo $this->Html->image('orgs/' . h($event['Event']['org']) . '.png', array('alt' => h($event['Event']['org']), 'title' => h($event['Event']['org']), 'style' => 'width:24px; height:24px'));
else echo $this->Html->tag('span', h($event['Event']['org']), array('class' => 'welcome', 'style' => 'float:left;'));
if (file_exists($imgAbsolutePath)) echo $this->Html->image('orgs/' . h($event['Org']['name']) . '.png', array('alt' => h($event['Org']['name']), 'title' => h($event['Org']['name']), 'style' => 'width:24px; height:24px'));
else echo $this->Html->tag('span', h($event['Org']['name']), array('class' => 'welcome', 'style' => 'float:left;'));
?>
&nbsp;
</td>