diff --git a/INSTALL/INSTALL.debian7.txt b/INSTALL/INSTALL.debian7.txt index 151d55a05..7fedee09a 100644 --- a/INSTALL/INSTALL.debian7.txt +++ b/INSTALL/INSTALL.debian7.txt @@ -137,14 +137,8 @@ service apache2 reload # We seriously recommend using only SSL ! # Check out the /var/www/MISP/INSTALL/apache.misp.ssl file for an example -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: -cp INSTALL/misp.logrotate /etc/logrotate.d/misp - -9/ MISP configuration +8/ MISP configuration --------------------- # There are 4 sample configuration files in /var/www/MISP/app/Config that need to be copied cd /var/www/MISP/app/Config diff --git a/INSTALL/INSTALL.debian8.txt b/INSTALL/INSTALL.debian8.txt index efeaa53ab..9a7fd981e 100644 --- a/INSTALL/INSTALL.debian8.txt +++ b/INSTALL/INSTALL.debian8.txt @@ -183,11 +183,6 @@ sudo a2ensite misp-ssl # Restart apache sudo systemctl restart apache2 -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: - sudo cp INSTALL/misp.logrotate /etc/logrotate.d/misp 9/ MISP configuration @@ -303,4 +298,3 @@ sudo ldconfig ## install pyzmq sudo pip install pyzmq - diff --git a/INSTALL/INSTALL.ubuntu1404.txt b/INSTALL/INSTALL.ubuntu1404.txt index b699371fc..715101aba 100644 --- a/INSTALL/INSTALL.ubuntu1404.txt +++ b/INSTALL/INSTALL.ubuntu1404.txt @@ -128,14 +128,8 @@ service apache2 reload # We seriously recommend using only SSL ! # Check out the apache.misp.ssl file for an example -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: -cp INSTALL/misp.logrotate /etc/logrotate.d/misp - -9/ MISP configuration +8/ MISP configuration --------------------- # There are 4 sample configuration files in /var/www/MISP/app/Config that need to be copied cd /var/www/MISP/app/Config diff --git a/INSTALL/INSTALL.ubuntu1604.txt b/INSTALL/INSTALL.ubuntu1604.txt index c184ae862..6441f7c67 100644 --- a/INSTALL/INSTALL.ubuntu1604.txt +++ b/INSTALL/INSTALL.ubuntu1604.txt @@ -184,11 +184,6 @@ sudo a2ensite misp-ssl # Restart apache sudo systemctl restart apache2 -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: - sudo cp INSTALL/misp.logrotate /etc/logrotate.d/misp 9/ MISP configuration diff --git a/INSTALL/MYSQL.sql b/INSTALL/MYSQL.sql index 4988e4053..ab49b8f10 100644 --- a/INSTALL/MYSQL.sql +++ b/INSTALL/MYSQL.sql @@ -29,12 +29,15 @@ CREATE TABLE IF NOT EXISTS `attributes` ( `timestamp` int(11) NOT NULL DEFAULT 0, `distribution` tinyint(4) NOT NULL DEFAULT 0, `sharing_group_id` int(11) NOT NULL, - `comment` text COLLATE utf8_bin NOT NULL, + `comment` text COLLATE utf8_bin, `deleted` tinyint(1) NOT NULL DEFAULT 0, + `disable_correlation` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `event_id` (`event_id`), INDEX `value1` (`value1`(255)), INDEX `value2` (`value2`(255)), + INDEX `type` (`type`), + INDEX `category` (`category`), INDEX `sharing_group_id` (`sharing_group_id`), UNIQUE INDEX `uuid` (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; @@ -137,6 +140,7 @@ CREATE TABLE IF NOT EXISTS `events` ( `locked` tinyint(1) NOT NULL DEFAULT 0, `threat_level_id` int(11) NOT NULL, `publish_timestamp` int(11) NOT NULL DEFAULT 0, + `disable_correlation` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE INDEX `uuid` (`uuid`), FULLTEXT INDEX `info` (`info`(255)), @@ -206,14 +210,26 @@ CREATE TABLE IF NOT EXISTS `feeds` ( `provider` varchar(255) COLLATE utf8_bin NOT NULL, `url` varchar(255) COLLATE utf8_bin NOT NULL, `rules` text COLLATE utf8_bin DEFAULT NULL, - `enabled` BOOLEAN NOT NULL, - `distribution` tinyint(4) NOT NULL, + `enabled` tinyint(1) DEFAULT 0, + `distribution` tinyint(4) NOT NULL DEFAULT 0, `sharing_group_id` int(11) NOT NULL DEFAULT 0, `tag_id` int(11) NOT NULL DEFAULT 0, - `default` tinyint(1) NOT NULL, - PRIMARY KEY (`id`) + `default` tinyint(1) DEFAULT 0, + `source_format` varchar(255) COLLATE utf8_bin DEFAULT 'misp', + `fixed_event` tinyint(1) NOT NULL DEFAULT 0, + `delta_merge` tinyint(1) NOT NULL DEFAULT 0, + `event_id` int(11) NOT NULL DEFAULT 0, + `publish` tinyint(1) NOT NULL DEFAULT 0, + `override_ids` tinyint(1) NOT NULL DEFAULT 0, + `settings` text NOT NULL DEFAULT '', + `input_source` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT "network", + `delete_local_file` tinyint(1) DEFAULT 0, + PRIMARY KEY (`id`), + INDEX `input_source` (`input_source`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + + -- ------------------------------------------------------- -- @@ -330,9 +346,9 @@ CREATE TABLE IF NOT EXISTS `logs` ( `model_id` int(11) NOT NULL, `action` varchar(20) COLLATE utf8_bin NOT NULL, `user_id` int(11) NOT NULL, - `change` text CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, - `email` varchar(255) COLLATE utf8_bin NOT NULL, - `org` varchar(255) COLLATE utf8_bin NOT NULL, + `change` text COLLATE utf8_bin NOT NULL DEFAULT "", + `email` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT "", + `org` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT "", `description` text CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; @@ -473,12 +489,12 @@ CREATE TABLE IF NOT EXISTS `servers` ( -- -------------------------------------------------------- -- --- Table structure for table `shadow_attributes` +-- Table structure for table ``)ributes` -- CREATE TABLE IF NOT EXISTS `shadow_attributes` ( `id` int(11) NOT NULL AUTO_INCREMENT, - `old_id` int(11) NOT NULL, + `old_id` int(11) DEFAULT 0, `event_id` int(11) NOT NULL, `type` varchar(100) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL, `category` varchar(255) COLLATE utf8_bin NOT NULL, @@ -494,6 +510,7 @@ CREATE TABLE IF NOT EXISTS `shadow_attributes` ( `deleted` tinyint(1) NOT NULL DEFAULT 0, `timestamp` int(11) NOT NULL DEFAULT 0, `proposal_to_delete` BOOLEAN NOT NULL DEFAULT 0, + `disable_correlation` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `event_id` (`event_id`), INDEX `event_uuid` (`event_uuid`), @@ -501,7 +518,9 @@ CREATE TABLE IF NOT EXISTS `shadow_attributes` ( INDEX `uuid` (`uuid`), INDEX `old_id` (`old_id`), INDEX `value1` (`value1`(255)), - INDEX `value2` (`value2`(255)) + INDEX `value2` (`value2`(255)), + INDEX `type` (`type`), + INDEX `category` (`category`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -- -------------------------------------------------------- @@ -599,15 +618,21 @@ CREATE TABLE `sharing_groups` ( -- CREATE TABLE IF NOT EXISTS sightings ( - id int(11) NOT NULL AUTO_INCREMENT, - attribute_id int(11) NOT NULL, - event_id int(11) NOT NULL, - org_id int(11) NOT NULL, - date_sighting bigint(20) NOT NULL, + `id` int(11) NOT NULL AUTO_INCREMENT, + `attribute_id` int(11) NOT NULL, + `event_id` int(11) NOT NULL, + `org_id` int(11) NOT NULL, + `date_sighting` bigint(20) NOT NULL, + `uuid` varchar(255) COLLATE utf8_bin DEFAULT "", + `source` varchar(255) COLLATE utf8_bin DEFAULT "", + `type` int(11) DEFAULT 0, PRIMARY KEY (id), - INDEX attribute_id (attribute_id), - INDEX event_id (event_id), - INDEX org_id (org_id) + INDEX `attribute_id` (`attribute_id`), + INDEX `event_id` (`event_id`), + INDEX `org_id` (`org_id`), + INDEX `uuid` (`uuid`), + INDEX `source` (`source`), + INDEX `type` (`type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; -- -------------------------------------------------------- @@ -622,6 +647,7 @@ CREATE TABLE IF NOT EXISTS `tags` ( `colour` varchar(7) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, `exportable` tinyint(1) NOT NULL, `org_id` tinyint(1) NOT NULL DEFAULT 0, + `hide_tag` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), FULLTEXT INDEX `name` (`name`), INDEX `org_id` (`org_id`) @@ -922,7 +948,7 @@ CREATE TABLE IF NOT EXISTS `whitelist` ( -- INSERT INTO `admin_settings` (`id`, `setting`, `value`) VALUES -(1, 'db_version', '2.4.51'); +(1, 'db_version', '2.4.66'); INSERT INTO `feeds` (`id`, `provider`, `name`, `url`, `distribution`, `default`, `enabled`) VALUES (1, 'CIRCL', 'CIRCL OSINT Feed', 'https://www.circl.lu/doc/misp/feed-osint', 3, 1, 0), diff --git a/INSTALL/misp.logrotate b/INSTALL/misp.logrotate deleted file mode 100644 index 37ba7611d..000000000 --- a/INSTALL/misp.logrotate +++ /dev/null @@ -1,9 +0,0 @@ -/var/www/MISP/app/tmp/logs/resque-*-error.log { - rotate 30 - dateext - missingok - notifempty - compress - weekly - copytruncate -} diff --git a/INSTALL/misplogrotate.te b/INSTALL/misplogrotate.te deleted file mode 100644 index 9d8d28ebc..000000000 --- a/INSTALL/misplogrotate.te +++ /dev/null @@ -1,8 +0,0 @@ -module misplogrotate 1.0; -require { - type logrotate_t; - type httpd_sys_content_t; - class dir { ioctl read getattr lock search open }; -} -#============= logrotate_t ============== -allow logrotate_t httpd_sys_content_t:dir { ioctl read getattr lock search open }; diff --git a/INSTALL/xINSTALL.centos6.txt b/INSTALL/xINSTALL.centos6.txt index ad98b350c..0fb59e19b 100644 --- a/INSTALL/xINSTALL.centos6.txt +++ b/INSTALL/xINSTALL.centos6.txt @@ -176,14 +176,8 @@ service iptables save # We seriously recommend using only SSL ! # Check out the apache.misp.ssl file for an example -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of its workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: -cp INSTALL/misp.logrotate /etc/logrotate.d/misp - -9/ MISP configuration +8/ MISP configuration --------------------- # There are 4 sample configuration files in /var/www/MISP/app/Config that need to be copied cd /var/www/MISP/app/Config diff --git a/INSTALL/xINSTALL.centos7.txt b/INSTALL/xINSTALL.centos7.txt index 56c95a8f5..55ff97882 100644 --- a/INSTALL/xINSTALL.centos7.txt +++ b/INSTALL/xINSTALL.centos7.txt @@ -193,24 +193,8 @@ firewall-cmd --reload # Add SSL support by running: yum install mod_ssl # Check out the apache.misp.ssl file for an example -8/ Log rotation ---------------- -# MISP saves the stdout and stderr of it's workers in /var/www/MISP/app/tmp/logs -# To rotate these logs install the supplied logrotate script: -cp INSTALL/misp.logrotate /etc/logrotate.d/misp - -# Now make logrotate work under SELinux as well -# Allow logrotate to modify the log files -semanage fcontext -a -t httpd_log_t "/var/www/MISP/app/tmp/logs(/.*)?" -chcon -R -t httpd_log_t /var/www/MISP/app/tmp/logs - -# Allow logrotate to read /var/www -checkmodule -M -m -o /tmp/misplogrotate.mod INSTALL/misplogrotate.te -semodule_package -o /tmp/misplogrotate.pp -m /tmp/misplogrotate.mod -semodule -i /tmp/misplogrotate.pp - -9/ MISP configuration +8/ MISP configuration --------------------- # There are 4 sample configuration files in /var/www/MISP/app/Config that need to be copied cd /var/www/MISP/app/Config diff --git a/PyMISP b/PyMISP index 26a8f4c66..a81f6b5c1 160000 --- a/PyMISP +++ b/PyMISP @@ -1 +1 @@ -Subproject commit 26a8f4c66230c0df10b2f9637e53ee1542a26f40 +Subproject commit a81f6b5c15e2effbc0b6118f1e1524b0950a576c diff --git a/app/Controller/AppController.php b/app/Controller/AppController.php index f50c2f770..4f6e4e819 100755 --- a/app/Controller/AppController.php +++ b/app/Controller/AppController.php @@ -46,9 +46,9 @@ class AppController extends Controller { public $helpers = array('Utility'); - private $__jsVersion = '2.4.62'; + private $__jsVersion = '2.4.66'; public $pyMispVersion = '2.4.65'; - public $phpmin = '5.5.9'; + public $phpmin = '5.6.5'; public $phprec = '7.0.0'; // Used for _isAutomation(), a check that returns true if the controller & action combo matches an action that is a non-xml and non-json automation method diff --git a/app/Controller/Component/ACLComponent.php b/app/Controller/Component/ACLComponent.php index ddd78d7aa..cb1d3fe2d 100644 --- a/app/Controller/Component/ACLComponent.php +++ b/app/Controller/Component/ACLComponent.php @@ -286,8 +286,12 @@ class ACLComponent extends Component { ), 'sightings' => array( 'add' => array('perm_add'), + 'advanced' => array('perm_add'), 'delete' => array('perm_add'), - 'index' => array('*') + 'index' => array('*'), + 'listSightings' => array('perm_add'), + 'quickDelete' => array('perm_add'), + 'viewSightings' => array('perm_add') ), 'tags' => array( 'add' => array('perm_tag_editor'), diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index 4684cbb50..2ef1bfa0d 100644 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -748,6 +748,8 @@ class EventsController extends AppController { $this->set('attributeFilter', isset($this->params['named']['attributeFilter']) ? $this->params['named']['attributeFilter'] : 'all'); $this->disableCache(); $this->layout = 'ajax'; + $this->loadModel('Sighting'); + $this->set('sightingTypes', $this->Sighting->type); $this->set('currentUri', $this->params->here); $this->render('/Elements/eventattribute'); } @@ -859,6 +861,8 @@ class EventsController extends AppController { } $this->set('contributors', $contributors); $this->set('typeGroups', array_keys($this->Event->Attribute->typeGroupings)); + $this->loadModel('Sighting'); + $this->set('sightingTypes', $this->Sighting->type); } public function view($id = null, $continue=false, $fromEvent=null) { @@ -3093,8 +3097,6 @@ class EventsController extends AppController { foreach (${$source} as $k => $attribute) { if ($attribute['type'] == 'ip-src/ip-dst') { $types = array('ip-src', 'ip-dst'); - } else if ($attribute['type'] == 'ip-src|port/ip-dst|port') { - $types = array('ip-src|port', 'ip-dst|port'); } else if ($attribute['type'] == 'malware-sample') { if (!isset($attribute['data_is_handled']) || !$attribute['data_is_handled']) { App::uses('FileAccessTool', 'Tools'); diff --git a/app/Controller/SightingsController.php b/app/Controller/SightingsController.php index b453e4204..1595e35d7 100644 --- a/app/Controller/SightingsController.php +++ b/app/Controller/SightingsController.php @@ -18,42 +18,110 @@ class SightingsController extends AppController { // takes an attribute ID or UUID public function add($id = false) { if (!$this->userRole['perm_add']) throw new MethodNotAllowedException('You are not authorised to add sightings data as you don\'t have write access.'); - if (!$this->request->is('post')) throw new MethodNotAllowedException('This action can only be accessed via a post request.'); - $now = time(); - $values = false; - $timestamp = false; - $error = false; - if ($id === 'stix') { - $result = $this->Sighting->handleStixSighting(file_get_contents('php://input')); - if ($result['success']) { - $result['data'] = json_decode($result['data'], true); - $timestamp = isset($result['data']['timestamp']) ? strtotime($result['data']['timestamp']) : $now; - if (isset($result['data']['values'])) $values = $result['data']['values']; - else $error = 'No valid values found could be extracted from the sightings document.'; - } $error = $result['message']; - } else { - if (isset($this->request->data['request'])) $this->request->data = $this->request->data['request']; - if (isset($this->request->data['Sighting'])) $this->request->data = $this->request->data['Sighting']; - $timestamp = isset($this->request->data['timestamp']) ? $this->request->data['timestamp'] : $now; - if (isset($this->request->data['value'])) $this->request->data['values'] = array($this->request->data['value']); - $values = isset($this->request->data['values']) ? $this->request->data['values'] : false; - if (!$id && isset($this->request->data['id'])) $id = $this->request->data['id']; - } - if (!$error) $result = $this->Sighting->saveSightings($id, $values, $timestamp, $this->Auth->user()); - if ($result == 0) $error = 'No valid attributes found that would match the sighting criteria.'; - - if ($this->request->is('ajax')) { - if ($error) { - $error_message = 'Could not add the Sighting. Reason: ' . $error; - return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $error_message)), 'status' => 200)); + if ($this->request->is('post')) { + $now = time(); + $values = false; + $timestamp = false; + $error = false; + if ($id === 'stix') { + $result = $this->Sighting->handleStixSighting(file_get_contents('php://input')); + if ($result['success']) { + $result['data'] = json_decode($result['data'], true); + $timestamp = isset($result['data']['timestamp']) ? strtotime($result['data']['timestamp']) : $now; + $type = '0'; + $source = ''; + if (isset($result['data']['values'])) $values = $result['data']['values']; + else $error = 'No valid values found could be extracted from the sightings document.'; + } $error = $result['message']; } else { - return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result . ' sighting' . (($result == 1) ? '' : 's') . ' added.')), 'status' => 200)); + if (isset($this->request->data['request'])) $this->request->data = $this->request->data['request']; + if (isset($this->request->data['Sighting'])) $this->request->data = $this->request->data['Sighting']; + if (!empty($this->request->data['date']) && !empty($this->request->data['time'])) { + $timestamp = DateTime::createFromFormat('Y-m-d:H:i:s', $this->request->data['date'] . ':' . $this->request->data['time']); + $timestamp = $timestamp->getTimestamp(); + } else { + $timestamp = isset($this->request->data['timestamp']) ? $this->request->data['timestamp'] : $now; + } + if (isset($this->request->data['value'])) $this->request->data['values'] = array($this->request->data['value']); + $values = isset($this->request->data['values']) ? $this->request->data['values'] : false; + if (!$id && isset($this->request->data['id'])) $id = $this->request->data['id']; + $type = isset($this->request->data['type']) ? $this->request->data['type'] : '0'; + $source = isset($this->request->data['source']) ? trim($this->request->data['source']) : ''; + } + if (!$error) $result = $this->Sighting->saveSightings($id, $values, $timestamp, $this->Auth->user(), $type, $source); + if ($result == 0) $error = 'No valid attributes found that would match the sighting criteria.'; + + if ($this->request->is('ajax')) { + if ($error) { + $error_message = 'Could not add the Sighting. Reason: ' . $error; + return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $error_message)), 'status' => 200)); + } else { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result . ' ' . $this->Sighting->type[$type] . (($result == 1) ? '' : 's') . ' added.')), 'status' => 200)); + } + } else { + if ($error) { + return $this->RestResponse->saveFailResponse('Sighting', 'add', $id, $error); + } else { + return $this->RestResponse->saveSuccessResponse('Sighting', 'add', $id, false, $result . ' ' . $this->Sighting->type[$type] . (($result == 1) ? '' : 's') . ' successfuly added.'); + } } } else { - if ($error) { - return $this->RestResponse->saveFailResponse('Sighting', 'add', $id, $error); + if (!$this->request->is('ajax')) { + throw new MethodNotAllowedException('This method is only accessible via POST requests and ajax GET requests.'); } else { - return $this->RestResponse->saveSuccessResponse('Sighting', 'add', $id, false, $result . ' sighting' . (($result == 1) ? '' : 's') . ' successfuly added.'); + $this->layout = false; + $this->loadModel('Attribute'); + $attributes = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id))); + if (empty($attributes)) { + throw new MethodNotAllowedExeption('Invalid Attribute.'); + } + $this->set('event_id', $attributes[0]['Attribute']['event_id']); + $this->set('id', $id); + $this->render('ajax/add_sighting'); + } + } + } + + public function advanced($id) { + if (empty($id)) { + throw new MethodNotAllowedException('Invalid attribute.'); + } + $input_id = $id; + $id = $this->Sighting->explodeIdList($id); + $this->loadModel('Attribute'); + $attributes = $this->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id))); + if (empty($attributes)) { + throw new MethodNotAllowedException('Invalid attribute.'); + } + $this->set('id', $input_id); + $this->render('/Sightings/ajax/advanced'); + } + + public function quickDelete($id, $rawId, $context) { + if (!$this->userRole['perm_modify_org']) throw new MethodNotAllowedException('You are not authorised to remove sightings data as you don\'t have permission to modify your organisation\'s data.'); + if (!$this->request->is('post')) { + $this->set('id', $id); + $sighting = $this->Sighting->find('first', array('conditions' => array('Sighting.id' => $id), 'recursive' => -1, 'fields' => array('Sighting.attribute_id'))); + $this->set('rawId', $rawId); + $this->set('context', $context); + $this->render('ajax/quickDeleteConfirmationForm'); + } else { + if (!isset($id)) { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => 'Invalid request.')), 'status' => 200)); + } else { + $sighting = $this->Sighting->find('first', array('conditions' => array('Sighting.id' => $id), 'recursive' => -1)); + if (empty($sighting)) { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => 'Invalid sighting.')), 'status' => 200)); + } + if (!$this->_isSiteAdmin() && $sighting['Sighting']['org_id'] != $this->Auth->user('org_id')) { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => 'Invalid sighting.')), 'status' => 200)); + } + $result = $this->Sighting->delete($id); + if ($result) { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Sighting deleted.')), 'status' => 200)); + } else { + return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'errors' => 'Sighting could not be deleted')), 'status' => 200)); + } } } } @@ -102,4 +170,107 @@ class SightingsController extends AppController { } return $this->RestResponse->viewData($sightings); } + + public function listSightings($id, $context = 'attribute', $org_id = false) { + $this->loadModel('Event'); + $rawId = $id; + $id = $this->Sighting->explodeIdList($id); + if ($context === 'attribute') { + $object = $this->Event->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0))); + } else { + // let's set the context to event here, since we reuse the variable later on for some additional lookups. + // Passing $context = 'org' could have interesting results otherwise... + $context = 'event'; + $object = $this->Event->fetchEvent($this->Auth->user(), $options = array('eventid' => $id, 'metadata' => true)); + } + if (empty($object)) { + throw new MethodNotAllowedException('Invalid object.'); + } + $conditions = array( + 'Sighting.' . $context . '_id' => $id + ); + if ($org_id) { + $conditions[] = array('Sighting.org_id' => $org_id); + } + $sightings = $this->Sighting->find('all', array( + 'conditions' => $conditions, + 'recursive' => -1, + 'contain' => array('Organisation.name'), + 'order' => array('Sighting.date_sighting DESC') + )); + $this->set('org_id', $org_id); + $this->set('rawId', $rawId); + $this->set('context', $context); + $this->set('types', array('Sighting', 'False-positive', 'Expiration')); + $this->set('sightings', $sightings); + $this->layout = false; + $this->render('ajax/list_sightings'); + } + + public function viewSightings($id, $context = 'attribute') { + $this->loadModel('Event'); + $id = $this->Sighting->explodeIdList($id); + if ($context === 'attribute') { + $attribute_id = $id; + $object = $this->Event->Attribute->fetchAttributes($this->Auth->user(), array('conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0))); + if (empty($object)) { + throw new MethodNotAllowedException('Invalid object.'); + } + $eventIds = array(); + foreach ($object as $k => $v) { + $eventIds[] = $v['Attribute']['event_id']; + } + $events = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $eventIds)); + } else { + $attribute_id = false; + // let's set the context to event here, since we reuse the variable later on for some additional lookups. + // Passing $context = 'org' could have interesting results otherwise... + $context = 'event'; + $events = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id)); + + } + if (empty($events)) { + throw new MethodNotAllowedException('Invalid object.'); + } + $results = array(); + $raw = array(); + foreach ($events as $event) { + $raw = array_merge($raw, $this->Sighting->attachToEvent($event, $this->Auth->user(), $attribute_id)); + } + foreach ($raw as $sighting) { + $results[$sighting['type']][date('Ymd', $sighting['date_sighting'])][] = $sighting; + } + $tsv = 'date\tSighting\tFalse-positive\n'; + $dataPoints = array(); + $startDate = (date('Ymd') - 3); + $details = array(); + foreach ($results as $type => $data) { + foreach ($data as $date => $sighting) { + if ($date < $startDate) { + $startDate = $date; + } + $temp = array(); + foreach ($sighting as $sightingInstance) { + if (!isset($sightingInstance['Organisation']['name'])) { + $org = 'Anonymised'; + } else { + $org = $sightingInstance['Organisation']['name']; + } + $temp[$org] = isset($temp[$org]) ? $temp[$org] + 1 : 1; + } + $dataPoints[$date][$type] = array('count' => count($sighting), 'details' => $temp); + } + } + for ($i = $startDate; $i < date('Ymd') + 1; $i++) { + if (checkdate(substr($i, 4, 2), substr($i, 6, 2), substr($i, 0, 4))) { + $tsv .= $i . '\t' . (isset($dataPoints[$i][0]['count']) ? $dataPoints[$i][0]['count'] : 0) . '\t' . (isset($dataPoints[$i][1]['count']) ? $dataPoints[$i][1]['count'] : 0) . '\n'; + $details[$i][0] = isset($dataPoints[$i][0]['details']) ? $dataPoints[$i][0]['details'] : array(); + $details[$i][1] = isset($dataPoints[$i][1]['details']) ? $dataPoints[$i][1]['details'] : array(); + } + } + $this->set('tsv', $tsv); + $this->set('results', $results); + $this->layout = 'ajax'; + $this->render('ajax/view_sightings'); + } } diff --git a/app/Controller/ThreadsController.php b/app/Controller/ThreadsController.php index d66ea5261..03fe8f594 100644 --- a/app/Controller/ThreadsController.php +++ b/app/Controller/ThreadsController.php @@ -22,21 +22,24 @@ class ThreadsController extends AppController { $thread_id = false; if ($result) { $thread_id = $this->Thread->find('first', array('recursive' => -1, 'conditions' => array('Thread.event_id' => $id), 'fields' => array('Thread.id'))); - if ($thread_id) { - if (!$this->_isRest()) { - $this->redirect(array('action' => 'view', $thread_id['Thread']['id'], true)); + if ($thread_id) { + $thread_id = $thread_id['Thread']['id']; } else { - return $this->__view($thread_id['Thread']['id'], false, false); - } - } else { - if ($this->_isRest()) { - return $this->RestResponse->viewData(array(), $this->response->type()); - } else { - throw new NotFoundException('Invalid Thread.'); + if ($this->_isRest()) { + return $this->RestResponse->viewData($array(), $this->response->type()); + } + $thread_id = false; } + } + if ($thread_id) { + $post_id = false; + if (isset($this->passedArgs['post_id'])) $post_id = $this->passedArgs['post_id']; + $response = $this->__view($thread_id, false, $post_id); + if ($this->_isRest()) { + return $response; } } else { - throw new NotFoundException('Invalid Event.'); + throw new NotFoundException('Invalid Thread.'); } } @@ -80,6 +83,7 @@ class ThreadsController extends AppController { throw new NotFoundException('Invalid thread.'); } $thread = $this->Thread->read(); + // If the thread belongs to an event, we have to make sure that the event's distribution level hasn't changed. // This is also a good time to update the thread's distribution level if that did happen. if (!empty($thread['Thread']['event_id'])) { diff --git a/app/Lib/Tools/ComplexTypeTool.php b/app/Lib/Tools/ComplexTypeTool.php index d4220c0ba..002aac695 100644 --- a/app/Lib/Tools/ComplexTypeTool.php +++ b/app/Lib/Tools/ComplexTypeTool.php @@ -8,7 +8,6 @@ class ComplexTypeTool { '/^h\[tt\]p/i' => 'http', '/\[\.\]/' => '.', '/\[dot\]/' => '.', - '/\(dot\)/' => '.', '/\\\\\./' => '.', '/\.+/' => '.' ); @@ -210,6 +209,7 @@ class ComplexTypeTool { // input2 from here on is the variable containing the original input with the port removed. It is only used by url / domain name / hostname / ip $comment = false; if (preg_match('/(:[0-9]{2,5})$/', $inputRefanged, $port)) { + $comment = 'On port ' . substr($port[0], 1); $inputRefangedNoPort = str_replace($port[0], '', $inputRefanged); $port = substr($port[0], 1); } else { @@ -217,13 +217,7 @@ class ComplexTypeTool { $inputRefangedNoPort = $inputRefanged; } // check for IP - if (filter_var($inputRefangedNoPort, FILTER_VALIDATE_IP)) { - if (isset($port)) { - return array('types' => array('ip-dst|port', 'ip-src|port', 'ip-src|port/ip-dst|port'), 'to_ids' => true, 'default_type' => 'ip-dst|port', 'comment' => $comment, 'value' => $inputRefangedNoPort . '|' . $port); - } else { - return array('types' => array('ip-dst', 'ip-src', 'ip-src/ip-dst'), 'to_ids' => true, 'default_type' => 'ip-dst', 'comment' => $comment, 'value' => $inputRefangedNoPort); - } - } + if (filter_var($inputRefangedNoPort, FILTER_VALIDATE_IP)) return array('types' => array('ip-dst', 'ip-src', 'ip-src/ip-dst'), 'to_ids' => true, 'default_type' => 'ip-dst', 'comment' => $comment, 'value' => $inputRefangedNoPort); if (strpos($inputRefangedNoPort, '/')) { $temp = explode('/', $inputRefangedNoPort); if (count($temp) == 2) { diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php index e82ec34df..1915ca347 100644 --- a/app/Model/AppModel.php +++ b/app/Model/AppModel.php @@ -41,7 +41,7 @@ class AppModel extends Model { 42 => false, 44 => false, 45 => false, 49 => true, 50 => false, 51 => false, 52 => false, 55 => true, 56 => true, 57 => true, 58 => false, 59 => false, 60 => false, 61 => false, 62 => false, - 63 => false, 64 => false, 65 => false + 63 => false, 64 => false, 65 => false, 66 => false ) ) ); @@ -78,6 +78,11 @@ class AppModel extends Model { case '2.4.55': $this->updateDatabase('addSightings'); break; + case '2.4.64': + $this->updateDatabase('2.4.64'); + $this->Sighting = Classregistry::init('Sighting'); + $this->Sighting->addUuids(); + break; default: $this->updateDatabase($command); break; @@ -557,8 +562,6 @@ class AppModel extends Model { $sqlArray[] = 'CREATE INDEX idx_attribute_tags_event_id ON attribute_tags (event_id);'; $sqlArray[] = 'CREATE INDEX idx_attribute_tags_tag_id ON attribute_tags (tag_id);'; } - $this->__dropIndex('attribute_tags', 'attribute_id'); - $this->__dropIndex('attribute_tags', 'tag_id'); break; case '2.4.61': $sqlArray[] = 'ALTER TABLE feeds ADD input_source varchar(255) COLLATE utf8_bin NOT NULL DEFAULT "network";'; @@ -603,7 +606,15 @@ class AppModel extends Model { break; case '2.4.66': $sqlArray[] = 'ALTER TABLE shadow_attributes CHANGE old_id old_id int(11) DEFAULT 0;'; - + $sqlArray[] = 'ALTER TABLE sightings ADD COLUMN uuid varchar(255) COLLATE utf8_bin DEFAULT "";'; + $sqlArray[] = 'ALTER TABLE sightings ADD COLUMN source varchar(255) COLLATE utf8_bin DEFAULT "";'; + $sqlArray[] = 'ALTER TABLE sightings ADD COLUMN type int(11) DEFAULT 0;'; + $indexArray[] = array('sightings', 'uuid'); + $indexArray[] = array('sightings', 'source'); + $indexArray[] = array('sightings', 'type'); + $indexArray[] = array('attributes', 'category'); + $indexArray[] = array('shadow_attributes', 'category'); + $indexArray[] = array('shadow_attributes', 'type'); break; case 'fixNonEmptySharingGroupID': $sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;'; @@ -653,11 +664,14 @@ class AppModel extends Model { )); } } - foreach ($indexArray as $iA) { - if (isset($iA[2])) { - $this->__addIndex($iA[0], $iA[1], $iA[2]); - } else { - $this->__addIndex($iA[0], $iA[1]); + if (!empty($indexArray)) { + if ($clean) $this->cleanCacheFiles(); + foreach ($indexArray as $iA) { + if (isset($iA[2])) { + $this->__addIndex($iA[0], $iA[1], $iA[2]); + } else { + $this->__addIndex($iA[0], $iA[1]); + } } } if ($clean) $this->cleanCacheFiles(); diff --git a/app/Model/Attribute.php b/app/Model/Attribute.php index 5911c3759..de99e38d5 100644 --- a/app/Model/Attribute.php +++ b/app/Model/Attribute.php @@ -1336,14 +1336,14 @@ class Attribute extends AppModel { } } } + $extraConditions = array(); if (!empty($ipValues)) { $extraConditions = array('OR' => array( 'Attribute.value1' => $ipValues, 'Attribute.value2' => $ipValues )); - return $extraConditions; } - return false; + return $extraConditions; } public function __afterSaveCorrelation($a, $full = false, $event = false) { diff --git a/app/Model/Event.php b/app/Model/Event.php index 9747f7fd0..9fba065d3 100644 --- a/app/Model/Event.php +++ b/app/Model/Event.php @@ -918,14 +918,8 @@ class Event extends AppModel { // cleanup the array from things we do not want to expose foreach (array('Org', 'org_id', 'orgc_id', 'proposal_email_lock', 'org', 'orgc') as $field) unset($event['Event'][$field]); foreach ($event['Event']['EventTag'] as $kt => $tag) { - if (!$tag['Tag']['exportable']) { - unset($event['Event']['EventTag'][$kt]); - } else { - unset($tag['org_id']); - $event['Event']['Tag'][] = $tag['Tag']; - } + if (!$tag['Tag']['exportable']) unset($event['Event']['EventTag'][$kt]); } - unset($event['Event']['EventTag']); // Add the local server to the list of instances in the SG if (isset($event['Event']['SharingGroup']) && isset($event['Event']['SharingGroup']['SharingGroupServer'])) { @@ -967,16 +961,6 @@ class Event extends AppModel { } } } - foreach ($attribute['AttributeTag'] as $kt => $tag) { - if (!$tag['Tag']['exportable']) { - unset($attribute['AttributeTag'][$kt]); - } else { - unset($tag['Tag']['org_id']); - $attribute['Tag'][] = $tag['Tag']; - } - } - unset($attribute['AttributeTag']); - // remove value1 and value2 from the output unset($attribute['value1']); @@ -1474,10 +1458,6 @@ class Event extends AppModel { } $event['ShadowAttribute'] = array_values($event['ShadowAttribute']); } - if ($event['Event']['orgc_id'] === $user['org_id'] && $user['Role']['perm_audit']) { - $UserEmail = $this->User->getAuthUser($event['Event']['user_id'])['email']; - $event['Event']['event_creator_email'] = $UserEmail; - } } return $results; } @@ -2455,8 +2435,7 @@ class Event extends AppModel { 'fields' => array('id', 'url', 'name') ) ), - ), - 'AttributeTag' => array('Tag') + ) ), 'EventTag' => array('Tag'), 'Org' => array('fields' => array('id', 'uuid', 'name', 'local')), diff --git a/app/Model/Feed.php b/app/Model/Feed.php index f9dd6367c..bf1743a56 100644 --- a/app/Model/Feed.php +++ b/app/Model/Feed.php @@ -655,20 +655,12 @@ class Feed extends AppModel { if (empty($data)) { return true; } - $prunedCopy = array(); foreach ($data as $key => $value) { - foreach ($prunedCopy as $copy) { - if ($copy['type'] == $value['type'] && $copy['category'] == $value['category'] && $copy['value'] == $value['value']) { - continue 2; - } - } $data[$key]['event_id'] = $event['Event']['id']; $data[$key]['distribution'] = $feed['Feed']['distribution']; $data[$key]['sharing_group_id'] = $feed['Feed']['sharing_group_id']; $data[$key]['to_ids'] = $feed['Feed']['override_ids'] ? 0 : $data[$key]['to_ids']; - $prunedCopy[] = $data[$key]; } - $data = $prunedCopy; if ($jobId) { $job = ClassRegistry::init('Job'); $job->id = $jobId; diff --git a/app/Model/Sighting.php b/app/Model/Sighting.php index db5b835b3..ac86735c2 100644 --- a/app/Model/Sighting.php +++ b/app/Model/Sighting.php @@ -28,19 +28,31 @@ class Sighting extends AppModel { ), ); + public $type = array( + 0 => 'sighting', + 1 => 'false-positive', + 2 => 'expiration' + ); + public function beforeValidate($options = array()) { parent::beforeValidate(); $date = date('Y-m-d H:i:s'); if (empty($this->data['Sighting']['id']) && empty($this->data['Sighting']['date_sighting'])) { $this->data['Sighting']['date_sighting'] = $date; } + if (empty($this->data['Sighting']['uuid'])) { + $this->data['Sighting']['uuid'] = CakeText::uuid(); + } return true; } - public function attachToEvent(&$event, $user) { + public function attachToEvent($event, $user, $attribute_id = false) { $ownEvent = false; if ($user['Role']['perm_site_admin'] || $event['Event']['org_id'] == $user['org_id']) $ownEvent = true; $conditions = array('Sighting.event_id' => $event['Event']['id']); + if ($attribute_id) { + $conditions[] = array('Sighting.attribute_id' => $attribute_id); + } if (!$ownEvent && (!Configure::read('Plugin.Sightings_policy') || Configure::read('Plugin.Sightings_policy') == 0)) { $conditions['Sighting.org_id'] = $user['org_id']; } @@ -81,10 +93,11 @@ class Sighting extends AppModel { return $sightings; } - public function saveSightings($id, $values, $timestamp, $user) { + public function saveSightings($id, $values, $timestamp, $user, $type = false, $source = false) { $conditions = array(); if ($id && $id !== 'stix') { - if (strlen($id) == 36) $conditions = array('Attribute.uuid' => $id); + $id = $this->explodeIdList($id); + if (!is_array($id) && strlen($id) == 36) $conditions = array('Attribute.uuid' => $id); else $conditions = array('Attribute.id' => $id); } else { if (!$values) return 0; @@ -100,12 +113,18 @@ class Sighting extends AppModel { if (empty($attributes)) return 0; $sightingsAdded = 0; foreach ($attributes as $attribute) { + if ($type === '2') { + // remove existing expiration by the same org if it exists + $this->deleteAll(array('Sighting.org_id' => $user['org_id'], 'Sighting.type' => $type, 'Sighting.attribute_id' => $attribute['Attribute']['id'])); + } $this->create(); $sighting = array( 'attribute_id' => $attribute['Attribute']['id'], 'event_id' => $attribute['Attribute']['event_id'], 'org_id' => $user['org_id'], 'date_sighting' => $timestamp, + 'type' => $type, + 'source' => $source ); $sightingsAdded += $this->save($sighting) ? 1 : 0; } @@ -139,4 +158,26 @@ class Sighting extends AppModel { public function generateRandomFileName() { return (new RandomTool())->random_str(FALSE, 12); } + + public function addUuids() { + $sightings = $this->find('all', array( + 'recursive' => -1, + 'conditions' => array('uuid' => '') + )); + $this->saveMany($sightings); + return true; + } + + public function explodeIdList($id) { + if (strpos($id, '|')) { + $id = explode('|', $id); + foreach ($id as $k => $v) { + if (!is_numeric($v)) { + unset($id[$k]); + } + } + $id = array_values($id); + } + return $id; + } } diff --git a/app/Model/User.php b/app/Model/User.php index f477ca9ba..b0c656f2e 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -900,9 +900,6 @@ App::uses('RandomTool', 'Tools'); 'conditions' => $conditions ); $orgs = $this->find($findType, $params); - if (empty($orgs)) { - return 0; - } if ($org_id !== false) { return $orgs[0]['num_members']; } else { @@ -957,7 +954,7 @@ App::uses('RandomTool', 'Tools'); if ($fixedPassword) { $password = $fixedPassword; } else { - $password = $this->generateRandomPassword(); + $password = $this->generateRandomPassword(); } $body = str_replace('$password', $password, $body); $body = str_replace('$username', $user['User']['email'], $body); diff --git a/app/View/Elements/eventattribute.ctp b/app/View/Elements/eventattribute.ctp index a4ecb4368..b556cfc9d 100644 --- a/app/View/Elements/eventattribute.ctp +++ b/app/View/Elements/eventattribute.ctp @@ -15,49 +15,69 @@ $attributeSightings = array(); $attributeOwnSightings = array(); $attributeSightingsPopover = array(); - if (isset($event['Sighting']) && !empty($event['Sighting'])) { + $sightingsData = array(); + $sparklineData = array(); + $startDates = array(); + if (!empty($event['Sighting'])) { foreach ($event['Sighting'] as $sighting) { - $attributeSightings[$sighting['attribute_id']][] = $sighting; - if (isset($sighting['org_id']) && $sighting['org_id'] == $me['org_id']) { - if (isset($attributeOwnSightings[$sighting['attribute_id']])) { - $attributeOwnSightings[$sighting['attribute_id']]['count']++; - if (!isset($attributeOwnSightings[$sighting['attribute_id']]['date']) || $attributeOwnSightings[$sighting['attribute_id']]['date'] < $sighting['date_sighting']) { - $attributeOwnSightings[$sighting['attribute_id']]['date'] = $sighting['date_sighting']; - } - } else { - $attributeOwnSightings[$sighting['attribute_id']]['count'] = 1; - $attributeOwnSightings[$sighting['attribute_id']]['date'] = $sighting['date_sighting']; + $type = $sightingTypes[$sighting['type']]; + if (!isset($sightingsData[$sighting['attribute_id']][$type])) { + $sightingsData[$sighting['attribute_id']][$type] = array('count' => 0); + } + $sightingsData[$sighting['attribute_id']][$type]['count']++; + $orgName = isset($sighting['Organisation']['name']) ? $sighting['Organisation']['name'] : 'Others'; + if (!isset($startDates[$sighting['attribute_id']]) || $startDates[$sighting['attribute_id']] > $sighting['date_sighting']) { + $startDates[$sighting['attribute_id']] = $sighting['date_sighting']; + } + if (!isset($sightingsData[$sighting['attribute_id']][$type]['orgs'][$orgName])) { + $sightingsData[$sighting['attribute_id']][$type]['orgs'][$orgName] = array('count' => 1, 'date' => $sighting['date_sighting']); + } else { + $sightingsData[$sighting['attribute_id']][$type]['orgs'][$orgName]['count']++; + if ($sightingsData[$sighting['attribute_id']][$type]['orgs'][$orgName]['date'] < $sighting['date_sighting']) { + $sightingsData[$sighting['attribute_id']][$type]['orgs'][$orgName]['date'] = $sighting['date_sighting']; } } - if (isset($sighting['org_id'])) { - if (isset($attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']])) { - $attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['count']++; - if (!isset($attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['date']) || $attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['date'] < $sighting['date_sighting']) { - $attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['date'] = $sighting['date_sighting']; - } - } else { - $attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['count'] = 1; - $attributeSightingsPopover[$sighting['attribute_id']][$sighting['Organisation']['name']]['date'] = $sighting['date_sighting']; - } + $date = date("Ymd", $sighting['date_sighting']); + if (!isset($sparklineData[$sighting['attribute_id']][$type][$date])) { + $sparklineData[$sighting['attribute_id']][$type][$date] = 1; } else { - if (isset($attributeSightingsPopover[$sighting['attribute_id']]['Other organisations'])) { - $attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['count']++; - if (!isset($attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['date']) || $attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['date'] < $sighting['date_sighting']) { - $attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['date'] = $sighting['date_sighting']; + $sparklineData[$sighting['attribute_id']][$type][$date]++; + } + } + $csv = array(); + $to = new DateTime(); + $from = new DateTime(); + foreach ($sparklineData as $aid => $data) { + foreach ($data as $type => $sighting) { + $from->setTimestamp(($startDates[$aid] - 259200)); + for ($date = clone $from; $date < $to; $date->modify('+1 day')) { + if (!isset($csv[$aid][$type])) { + $csv[$aid][$type] = 'Date,Close\n'; + } + $currentDate = $date->format('Ymd'); + if (isset($sighting[$currentDate])) { + $csv[$aid][$type] .= $currentDate . ',' . $sighting[$currentDate] . '\n'; + } else { + $csv[$aid][$type] .= $currentDate . ',0\n'; } - } else { - $attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['count'] = 1; - $attributeSightingsPopover[$sighting['attribute_id']]['Other organisations']['date'] = $sighting['date_sighting']; } } } - if (!empty($attributeSightingsPopover)) { - $attributeSightingsPopoverText = array(); - foreach ($attributeSightingsPopover as $aid => &$attribute) { - $attributeSightingsPopoverText[$aid] = ''; - foreach ($attribute as $org => $data) { - $attributeSightingsPopoverText[$aid] .= '' . h($org) . ': ' . h($data['count']) . ' (' . date('Y-m-d H:i:s', $data['date']) . ')
'; + unset($sparklineData); + foreach ($sightingsData as $aid => $data) { + $sightingsData[$aid]['html'] = ''; + foreach ($data as $type => $typeData) { + $name = (($type != 'expiration') ? Inflector::pluralize($type) : $type); + $sightingsData[$aid]['html'] .= '' . ucfirst(h($name)) . '
'; + foreach ($typeData['orgs'] as $org => $orgData) { + $extra = (($org == $me['Organisation']['name']) ? " class= 'bold'" : ""); + if ($type == 'expiration') { + $sightingsData[$aid]['html'] .= '' . h($org) . ': ' . date('Y-m-d H:i:s', $orgData['date']) . '
'; + } else { + $sightingsData[$aid]['html'] .= '' . h($org) . ': ' . h($orgData['count']) . ' (' . date('Y-m-d H:i:s', $orgData['date']) . ')
'; + } } + $sightingsData[$aid]['html'] .= '
'; } } } @@ -128,11 +148,14 @@
- - - - - + + + + + + + +
@@ -184,6 +207,7 @@ Paginator->sort('distribution');?> Sightings + Activity Actions @@ -279,7 +303,7 @@
- +
' . $filenameHash[1]; + if (isset($filenameHash[1])) { + $separator = '
'; + if (in_array($object['type'], array('ip-dst|port', 'ip-src|port'))) { + $separator = ':'; + } + echo $separator . h($filenameHash[1]); + } } else if ('vulnerability' == $object['type']) { if (! is_null(Configure::read('MISP.cveurl'))) { $cveUrl = Configure::read('MISP.cveurl'); @@ -452,25 +482,48 @@ endif; if (Configure::read('Plugin.Sightings_enable') !== false): ?> - + Form->create('Sighting', array('id' => 'Sighting_' . $object['id'], 'url' => '/sightings/add/' . $object['id'], 'style' => 'display:none;')); + echo $this->Form->input('type', array('label' => false, 'id' => 'Sighting_' . $object['id'] . '_type')); echo $this->Form->end(); ?> -   - - + +   +   +   + + - - + + ' . h($s) . '/' . h($f) . '/' . h($e) . ')'; ?> + + element('sparkline', array('id' => $object['id'], 'csv' => $temp)); + } + ?> + @@ -588,8 +641,6 @@ attributes or the appropriate distribution level. If you think there is a mistak popoverStartup(); $('.select_attribute').removeAttr('checked'); $('.select_proposal').removeAttr('checked'); - $('.mass-select').hide(); - $('.mass-proposal-select').hide(); $('.select_attribute').click(function(e) { if ($(this).is(':checked')) { if (e.shiftKey) { @@ -620,6 +671,20 @@ attributes or the appropriate distribution level. If you think there is a mistak $('.screenshot').click(function() { screenshotPopup($(this).attr('src'), $(this).attr('title')); }); + $('.sightings_advanced_add').click(function() { + var selected = []; + var object_id = $(this).data('object-id'); + if (object_id == 'selected') { + $(".select_attribute").each(function() { + if ($(this).is(":checked")) { + selected.push($(this).data("id")); + } + }); + object_id = selected.join('|'); + } + url = "" + "/sightings/advanced/" + object_id; + genericPopup(url, '#screenshot_box'); + }); }); +Html->script('d3'); + //echo $this->Html->css('sightingstyle'); +?> +
+ diff --git a/app/View/Events/add.ctp b/app/View/Events/add.ctp index 3f78ce072..fc02495a7 100644 --- a/app/View/Events/add.ctp +++ b/app/View/Events/add.ctp @@ -67,21 +67,21 @@ echo $this->Form->end(); foreach ($formInfoTypes as $formInfoType => $humanisedName) { echo 'var ' . $formInfoType . 'FormInfoValues = {' . PHP_EOL; foreach ($info[$formInfoType] as $key => $formInfoData) { - echo '"' . $key . '": "' . h($formInfoData['key']) . ': ' . h($formInfoData['desc']) . '
",' . PHP_EOL; + echo '"' . $key . '": "' . h($formInfoData['key']) . ': ' . h($formInfoData['desc']) . '
",' . PHP_EOL; } echo '}' . PHP_EOL; } ?> - + $('#EventDistribution').change(function() { if ($('#EventDistribution').val() == 4) $('#SGContainer').show(); else $('#SGContainer').hide(); }); - + $("#EventDistribution, #EventAnalysis, #EventThreatLevelId").change(function() { initPopoverContent('Event'); }); - + $(document).ready(function() { if ($('#EventDistribution').val() == 4) $('#SGContainer').show(); else $('#SGContainer').hide(); diff --git a/app/View/Events/ajax/handleSelected.ctp b/app/View/Events/ajax/handleSelected.ctp new file mode 100644 index 000000000..a11deeaba --- /dev/null +++ b/app/View/Events/ajax/handleSelected.ctp @@ -0,0 +1,30 @@ +
+ Form->create($model, array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => $url)); + echo $this->Form->input($varName, array( + 'type' => 'text', + 'value' => 'test', + 'style' => 'display:none;', + 'label' => false, + )); + ?> + +
+

+ + + + + + +
+ Yes + + + No +
+
+ Form->end(); + ?> +
diff --git a/app/View/Feeds/add.ctp b/app/View/Feeds/add.ctp index 422f8bae3..c4b025351 100644 --- a/app/View/Feeds/add.ctp +++ b/app/View/Feeds/add.ctp @@ -16,7 +16,7 @@ 'class' => 'form-control span6' )); echo $this->Form->input('input_source', array( - 'label' => 'Input Source', + 'label' => 'Source Format', 'div' => 'input clear', 'options' => array('network' => 'Network', 'local' => 'Local'), 'class' => 'form-control span6' diff --git a/app/View/Feeds/edit.ctp b/app/View/Feeds/edit.ctp index ce3197bfc..62a4dfe68 100644 --- a/app/View/Feeds/edit.ctp +++ b/app/View/Feeds/edit.ctp @@ -16,7 +16,7 @@ 'class' => 'form-control span6' )); echo $this->Form->input('input_source', array( - 'label' => 'Input Source', + 'label' => 'Source Format', 'div' => 'input clear', 'options' => array('network' => 'Network', 'local' => 'Local'), 'class' => 'form-control span6' @@ -187,9 +187,12 @@ var rules = {"pull": {"tags": {"OR":[], "NOT":[]}, "orgs": {"OR":[], "NOT":[]}}} var validOptions = ['pull']; var validFields = ['tags', 'orgs']; var modelContext = 'Feed'; +var tags = []; +var orgs = []; $(document).ready(function() { rules = convertServerFilterRules(rules); + serverRulePopulateTagPicklist(); feedDistributionChange(); $("#pull_modify").click(function() { serverRuleFormActivate('pull'); diff --git a/app/View/Layouts/default.ctp b/app/View/Layouts/default.ctp index 74452a609..12b3d16f7 100644 --- a/app/View/Layouts/default.ctp +++ b/app/View/Layouts/default.ctp @@ -34,8 +34,8 @@
-
+
element('global_menu'); diff --git a/app/View/Roles/admin_add.ctp b/app/View/Roles/admin_add.ctp index 555da1a3a..6596c0909 100644 --- a/app/View/Roles/admin_add.ctp +++ b/app/View/Roles/admin_add.ctp @@ -24,9 +24,6 @@ echo $this->Form->end(); echo $this->element('side_menu', array('menuList' => 'admin', 'menuItem' => 'addRole')); $this->Js->get('#RolePermission')->event('change', 'deactivateActions()'); foreach ($permFlags as $k => $flag) { - if ($k == 'perm_audit' || $k == 'perm_auth') { - continue; - } if ($k !== 'perm_site_admin') $this->Js->get('#' . $flag['id'])->event('change', 'checkPerms("' . $flag['id'] . '")'); else $this->Js->get('#RolePermSiteAdmin')->event('change', 'checkPerms("RolePermSiteAdmin");activateAll();'); } diff --git a/app/View/Roles/admin_edit.ctp b/app/View/Roles/admin_edit.ctp index dc375a277..b1c625999 100644 --- a/app/View/Roles/admin_edit.ctp +++ b/app/View/Roles/admin_edit.ctp @@ -24,9 +24,6 @@ echo $this->element('side_menu', array('menuList' => 'admin', 'menuItem' => 'editRole')); $this->Js->get('#RolePermission')->event('change', 'deactivateActions()'); foreach ($permFlags as $k => $flag) { - if ($k == 'perm_audit' || $k == 'perm_auth') { - continue; - } if ($k !== 'perm_site_admin') $this->Js->get('#' . $flag['id'])->event('change', 'checkPerms("' . $flag['id'] . '")'); else $this->Js->get('#RolePermSiteAdmin')->event('change', 'checkPerms("RolePermSiteAdmin");activateAll();'); } diff --git a/app/View/Sightings/ajax/add_sighting.ctp b/app/View/Sightings/ajax/add_sighting.ctp new file mode 100644 index 000000000..3c5f80eee --- /dev/null +++ b/app/View/Sightings/ajax/add_sighting.ctp @@ -0,0 +1,37 @@ +

Add Sighting

+ +Form->create('Sighting', array('id', 'url' => '/sightings/add/' . urlencode(h($id)), 'style' => 'margin-bottom:0px;')); + echo $this->Form->input('type', array( + 'options' => array('Sighting', 'Fase-positive', 'Expiration'), + 'default' => 0, + 'style' => 'width:230px;margin-right:0px;' + )); + echo $this->Form->input('source', array( + 'placeholder' => 'honeypot, IDS sensor id, SIEM,...', + 'style' => 'width:447px;', + 'div' => array('style' => 'width:457px !important;') + )); + echo $this->Form->label('Sighting date'); + echo $this->Form->input('date', array( + 'type' => 'text', + 'id' => 'datepicker', + 'default' => date('Y-m-d'), + 'style' => 'width:110px;', + 'div' => array('style' => 'width:120px !important;'), + 'label' => false + )); + echo $this->Form->input('time', array( + 'class' => 'input-mini', + 'default' => date('H:i:s'), + 'id' => 'timepicker', + 'style' => 'width:120px;', + 'div' => array('style' => 'width:120px !important;'), + 'label' => false + )); +?> +Add +
+Form->end(); +?> diff --git a/app/View/Sightings/ajax/advanced.ctp b/app/View/Sightings/ajax/advanced.ctp new file mode 100644 index 000000000..dbb5d1881 --- /dev/null +++ b/app/View/Sightings/ajax/advanced.ctp @@ -0,0 +1,59 @@ +
+

+
+ Graph + All + My org + Add sighting +
+
+
+ Cancel +
+
+
+ + +Js->writeBuffer(); // Write cached scripts diff --git a/app/View/Sightings/ajax/list_sightings.ctp b/app/View/Sightings/ajax/list_sightings.ctp new file mode 100644 index 000000000..2ab5c3af8 --- /dev/null +++ b/app/View/Sightings/ajax/list_sightings.ctp @@ -0,0 +1,52 @@ +
+ +

Galaxies

+ + + + + + + + + + + + + + + + + + + + + +
DateOrganisationTypeSourceEvent IDAttribute IDActions
+ Html->image('orgs/' . h($item['Organisation']['name']) . '.png', array('alt' => h($item['Organisation']['name']), 'title' => h($item['Organisation']['name']), 'style' => 'width:24px; height:24px')); + else: + echo h($item['Organisation']['name']); + endif; + + ?> + + +
+
diff --git a/app/View/Sightings/ajax/quickDeleteConfirmationForm.ctp b/app/View/Sightings/ajax/quickDeleteConfirmationForm.ctp new file mode 100644 index 000000000..ca22c2788 --- /dev/null +++ b/app/View/Sightings/ajax/quickDeleteConfirmationForm.ctp @@ -0,0 +1,24 @@ +
+ Form->create('Sighting', array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => '/sightings/quickDelete/' . $id . '/' . urlencode($rawId) . '/' . $context)); + ?> + Remove Sighting +
+

Remove sighting ()?

+ + + + + + +
+ Yes + + + No +
+
+ Form->end(); + ?> +
diff --git a/app/View/Sightings/ajax/view_sightings.ctp b/app/View/Sightings/ajax/view_sightings.ctp new file mode 100644 index 000000000..7c33009f2 --- /dev/null +++ b/app/View/Sightings/ajax/view_sightings.ctp @@ -0,0 +1,150 @@ +Html->script('d3'); + echo $this->Html->css('sightingstyle'); +?> +
+ diff --git a/app/View/Whitelists/admin_index.ctp b/app/View/Whitelists/admin_index.ctp index e19ddc61f..34aac3f0d 100644 --- a/app/View/Whitelists/admin_index.ctp +++ b/app/View/Whitelists/admin_index.ctp @@ -1,6 +1,5 @@
-

Signature Whitelist

-

Regex entries (in the standard php regex /{regex}/{modifier} format) entered below will restrict matching attributes from being included in the IDS flag sensitive exports (such as NIDS exports).

+

Import Whitelist