Merge branch 'feature/enhanced_sightings' into 2.4

pull/1967/head
iglocska 2017-02-17 13:35:06 +01:00
commit f0e1a27b7d
41 changed files with 1014 additions and 272 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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),

View File

@ -1,9 +0,0 @@
/var/www/MISP/app/tmp/logs/resque-*-error.log {
rotate 30
dateext
missingok
notifempty
compress
weekly
copytruncate
}

View File

@ -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 };

View File

@ -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

View File

@ -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

2
PyMISP

@ -1 +1 @@
Subproject commit 26a8f4c66230c0df10b2f9637e53ee1542a26f40
Subproject commit a81f6b5c15e2effbc0b6118f1e1524b0950a576c

View File

@ -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

View File

@ -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'),

View File

@ -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');

View File

@ -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');
}
}

View File

@ -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'])) {

View File

@ -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) {

View File

@ -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();

View File

@ -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) {

View File

@ -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')),

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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] .= '<span class=\'bold\'>' . h($org) . '</span>: <span class=\'green bold\'>' . h($data['count']) . ' (' . date('Y-m-d H:i:s', $data['date']) . ')</span><br />';
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'] .= '<span class=\'blue bold\'>' . ucfirst(h($name)) . '</span><br />';
foreach ($typeData['orgs'] as $org => $orgData) {
$extra = (($org == $me['Organisation']['name']) ? " class= 'bold'" : "");
if ($type == 'expiration') {
$sightingsData[$aid]['html'] .= '<span ' . $extra . '>' . h($org) . '</span>: <span class=\'orange bold\'>' . date('Y-m-d H:i:s', $orgData['date']) . '</span><br />';
} else {
$sightingsData[$aid]['html'] .= '<span ' . $extra . '>' . h($org) . '</span>: <span class=\'' . (($type == 'sighting') ? 'green' : 'red') . ' bold\'>' . h($orgData['count']) . ' (' . date('Y-m-d H:i:s', $orgData['date']) . ')</span><br />';
}
}
$sightingsData[$aid]['html'] .= '<br />';
}
}
}
@ -128,11 +148,14 @@
<div id="attributeList" class="attributeListContainer">
<div class="tabMenu tabMenuEditBlock noPrint">
<span id="create-button" title="Add attribute" class="icon-plus useCursorPointer" onClick="clickCreateButton(<?php echo $event['Event']['id']; ?>, '<?php echo $possibleAction; ?>');"></span>
<span id="multi-edit-button" title="Edit selected Attributes" class="icon-edit mass-select useCursorPointer" onClick="editSelectedAttributes(<?php echo $event['Event']['id']; ?>);"></span>
<span id="multi-tag-button" title="Tag selected Attributes" class="icon-tag mass-select useCursorPointer" onClick="getPopup('selected/true', 'tags', 'selectTaxonomy');"></span>
<span id="multi-delete-button" title="Delete selected Attributes" class = "icon-trash mass-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'deleteAttributes');"></span>
<span id="multi-accept-button" title="Accept selected Proposals" class="icon-ok mass-proposal-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'acceptProposals');"></span>
<span id="multi-discard-button" title="Discard selected Proposals" class = "icon-remove mass-proposal-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'discardProposals');"></span>
<span id="multi-edit-button" title="Edit selected Attributes" class="hidden icon-edit mass-select useCursorPointer" onClick="editSelectedAttributes(<?php echo $event['Event']['id']; ?>);"></span>
<span id="multi-tag-button" title="Tag selected Attributes" class="hidden icon-tag mass-select useCursorPointer" onClick="getPopup('selected/true', 'tags', 'selectTaxonomy');"></span>
<span id="multi-delete-button" title="Delete selected Attributes" class="hidden icon-trash mass-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'deleteAttributes');"></span>
<span id="multi-accept-button" title="Accept selected Proposals" class="hidden icon-ok mass-proposal-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'acceptProposals');"></span>
<span id="multi-discard-button" title="Discard selected Proposals" class="hidden icon-remove mass-proposal-select useCursorPointer" onClick="multiSelectAction(<?php echo $event['Event']['id']; ?>, 'discardProposals');"></span>
<?php if (Configure::read('Plugin.Sightings_enable')): ?>
<span id="multi-sighting-button" title="Sightings display for selected attributes" class="hidden icon-wrench mass-select useCursorPointer sightings_advanced_add" data-object-id="selected"></span>
<?php endif; ?>
</div>
<div class="tabMenu tabMenuToolsBlock noPrint">
<?php if ($mayModify): ?>
@ -184,6 +207,7 @@
<th title="<?php echo $attrDescriptions['distribution']['desc'];?>"><?php echo $this->Paginator->sort('distribution');?></th>
<?php if (Configure::read('Plugin.Sightings_enable') !== false): ?>
<th>Sightings</th>
<th>Activity</th>
<?php endif; ?>
<th class="actions">Actions</th>
</tr>
@ -279,7 +303,7 @@
<?php echo h($object['type']); ?>
</div>
</td>
<td id="<?php echo h($currentType) . '_' . h($object['id']) . '_container'; ?>" class="showspaces <?php echo $extra; ?> limitedWidth">
<td id="<?php echo h($currentType) . '_' . h($object['id']) . '_container'; ?>" class="showspaces <?php echo $extra; ?> limitedWidth shortish">
<div id = "<?php echo $currentType . '_' . $object['id'] . '_value_placeholder'; ?>" class = "inline-field-placeholder"></div>
<?php
if ('attachment' !== $object['type'] && 'malware-sample' !== $object['type']) $editable = ' ondblclick="activateField(\'' . $currentType . '\', \'' . $object['id'] . '\', \'value\', \'' . $event['Event']['id'] . '\');"';
@ -311,7 +335,13 @@
} else if (strpos($object['type'], '|') !== false) {
$filenameHash = explode('|', $object['value']);
echo h($filenameHash[0]);
if (isset($filenameHash[1])) echo '<br />' . $filenameHash[1];
if (isset($filenameHash[1])) {
$separator = '<br />';
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):
?>
<td class="short <?php echo $extra;?>">
<td class="shortish <?php echo $extra;?>">
<span id="sightingForm_<?php echo h($object['id']);?>">
<?php
if ($object['objectType'] == 0):
echo $this->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();
?>
</span>
<span class="icon-thumbs-up useCursorPointer" onClick="addSighting('<?php echo h($object['id']); ?>', '<?php echo h($event['Event']['id']);?>', '<?php echo h($page); ?>');">&nbsp;</span>
<span id="sightingCount_<?php echo h($object['id']); ?>" class="bold sightingsCounter_<?php echo h($object['id']); ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?php echo isset($attributeSightingsPopoverText[$object['id']]) ? $attributeSightingsPopoverText[$object['id']] : ''; ?>">
<?php echo (!empty($attributeSightings[$object['id']]) ? count($attributeSightings[$object['id']]) : 0); ?>
<?php
$temp = array();
if (isset($csv[$object['id']]['sighting'])) {
$temp[0] = $csv[$object['id']]['sighting'];
}
if (isset($csv[$object['id']]['false-positive'])) {
$temp[1] = $csv[$object['id']]['false-positive'];
}
?>
<span class="icon-thumbs-up useCursorPointer" onClick="addSighting('0', '<?php echo h($object['id']); ?>', '<?php echo h($event['Event']['id']);?>', '<?php echo h($page); ?>');">&nbsp;</span>
<span class="icon-thumbs-down useCursorPointer" onClick="addSighting('1', '<?php echo h($object['id']); ?>', '<?php echo h($event['Event']['id']);?>', '<?php echo h($page); ?>');">&nbsp;</span>
<span class="icon-wrench useCursorPointer sightings_advanced_add" data-object-id="<?php echo h($object['id']); ?>">&nbsp;</span>
<span id="sightingCount_<?php echo h($object['id']); ?>" class="bold sightingsCounter_<?php echo h($object['id']); ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?php echo isset($sightingsData[$object['id']]['html']) ? $sightingsData[$object['id']]['html'] : ''; ?>">
<?php
$s = (!empty($sightingsData[$object['id']]['sighting']['count']) ? $sightingsData[$object['id']]['sighting']['count'] : 0);
$f = (!empty($sightingsData[$object['id']]['false-positive']['count']) ? $sightingsData[$object['id']]['false-positive']['count'] : 0);
$e = (!empty($sightingsData[$object['id']]['expiration']['count']) ? $sightingsData[$object['id']]['expiration']['count'] : 0);
?>
</span>
<span id="ownSightingCount_<?php echo h($object['id']); ?>" class="bold green sightingsCounter_<?php echo h($object['id']); ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?php echo isset($attributeSightingsPopoverText[$object['id']]) ? $attributeSightingsPopoverText[$object['id']] : ''; ?>">
<?php echo '(' . (isset($attributeOwnSightings[$object['id']]['count']) ? $attributeOwnSightings[$object['id']]['count'] : 0) . ')'; ?>
<span id="ownSightingCount_<?php echo h($object['id']); ?>" class="bold sightingsCounter_<?php echo h($object['id']); ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?php echo isset($sightingsData[$object['id']]['html']) ? $sightingsData[$object['id']]['html'] : ''; ?>">
<?php echo '(<span class="green">' . h($s) . '</span>/<span class="red">' . h($f) . '</span>/<span class="orange">' . h($e) . '</span>)'; ?>
</span>
<?php
endif;
?>
</td>
<td class="short <?php echo $extra; ?>">
<?php
if ($object['objectType'] == 0) {
echo $this->element('sparkline', array('id' => $object['id'], 'csv' => $temp));
}
?>
</td>
<?php
endif;
?>
@ -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 = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id;
genericPopup(url, '#screenshot_box');
});
});
</script>
<?php

View File

@ -0,0 +1,48 @@
<!--
Modified version of http://www.tnoda.com/blog/2013-12-19
-->
<?php
echo $this->Html->script('d3');
//echo $this->Html->css('sightingstyle');
?>
<div id="spark_<?php echo h($id); ?>"></div>
<script>
var width = 100;
var height = 25;
var x = d3.scale.linear().range([0, width - 2]);
var y = d3.scale.linear().range([height - 4, 0]);
var parseDate = d3.time.format("%Y%m%d").parse;
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
function sparkline(elemId, data) {
data.forEach(function(d) {
d.date = parseDate(d.Date);
d.close = +d.Close;
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain(d3.extent(data, function(d) { return d.close; }));
var svg = d3.select(elemId)
.append('svg')
.attr('width', width)
.attr('height', height)
.append('g')
.attr('transform', 'translate(0, 2)');
svg.append('path')
.datum(data)
.attr('class', 'sparkline')
.attr('d', line);
svg.append('circle')
.attr('class', 'sparkcircle')
.attr('cx', x(data[data.length - 1].date))
.attr('cy', y(data[data.length - 1].close))
.attr('r', 2);
}
var myData = "<?php echo isset($csv[0]) ? $csv[0] : ''; ?>";
if (myData != '') {
var data = d3.csv.parse(myData);
sparkline('#spark_<?php echo h($id); ?>', data);
}
</script>

View File

@ -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 . '": "<span class=\"blue bold\">' . h($formInfoData['key']) . '</span>: ' . h($formInfoData['desc']) . '<br />",' . PHP_EOL;
echo '"' . $key . '": "<span class=\"blue bold\">' . h($formInfoData['key']) . '</span>: ' . h($formInfoData['desc']) . '<br />",' . 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();

View File

@ -0,0 +1,30 @@
<div class="confirmation">
<?php
echo $this->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,
));
?>
<legend><?php echo h(Inflector::humanize($action)); ?></legend>
<div style="padding-left:5px;padding-right:5px;padding-bottom:5px;">
<p><?php echo h($message); ?></p>
<table>
<tr>
<td style="vertical-align:top">
<span id="PromptYesButton" class="btn btn-primary" onClick="multiSelectAction('<?php echo h($id); ?>', '<?php echo h($action); ?>');">Yes</span>
</td>
<td style="width:540px;">
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="PromptNoButton" onClick="cancelPrompt();">No</span>
</td>
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
</div>

View File

@ -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'

View File

@ -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');

View File

@ -34,8 +34,8 @@
</head>
<body>
<div id="popover_form" class="ajax_popover_form"></div>
<div id="confirmation_box" class="confirmation_box"></div>
<div id="screenshot_box" class="screenshot_box"></div>
<div id="confirmation_box" class="confirmation_box"></div>
<div id="gray_out" class="gray_out"></div>
<div id="container">
<?php echo $this->element('global_menu');

View File

@ -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();');
}

View File

@ -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();');
}

View File

@ -0,0 +1,37 @@
<h3>Add Sighting</h3>
<div id="sightingsEventId" class="hidden" data-event-id="<?php echo h($event_id); ?>"></div>
<?php
echo $this->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
));
?>
<span id="submitButton" class="btn btn-primary" onClick="submitPopoverForm('<?php echo h($id);?>', 'addSighting', '<?php echo h($event_id); ?>')">Add</span>
<div class="input clear"></div>
<?php
echo $this->Form->end();
?>

View File

@ -0,0 +1,59 @@
<div class="sightings_advanced">
<div class="popover-legend"><p><?php echo __('Sighting details'); ?></p></div>
<div style="margin:10px;">
<span id="sightingsGraphToggle" class="btn btn-primary qet toggle-left sightingsToggle" data-type="graph">Graph</span>
<span id="sightingsListAllToggle" class="btn btn-inverse qet toggle sightingsToggle" data-type="all">All</span>
<span id="sightingsListMyToggle" class="btn btn-inverse qet toggle sightingsToggle" data-type="org">My org</span>
<span id="sightingsAddToggle" class="btn btn-inverse qet toggle-right sightingsToggle" data-type="add">Add sighting</span>
</div>
<div id="mainContents" style="margin-top:40px;padding:10px;">
<div id="sightingsData" class="sightingTab"></div>
<span style="float:right;margin-bottom:10px;" class="btn btn-inverse" id="cancel">Cancel</span>
</div>
</div>
</div>
<script type="text/javascript">
$(document).ready(function() {
id = "<?php echo h($id); ?>";
$('#cancel').click(function() {
cancelPopoverForm();
});
$('#datepicker').datepicker({
startDate: '-180d',
endDate: '+1d',
orientation: 'bottom',
autoclose: true,
format: 'yyyy-mm-dd'
});
$('#timepicker').timepicker({
minuteStep: 1,
showMeridian: false,
showSeconds: true,
maxHours: 24
});
loadSightingGraph(id, "attribute");
});
$('.sightingsToggle').click(function() {
$('.sightingsToggle').removeClass('btn-primary');
$('.sightingsToggle').addClass('btn-inverse');
$(this).removeClass('btn-inverse');
$(this).addClass('btn-primary');
var type = $(this).data('type');
$('.sightingTab').empty();
if (type == 'graph') {
loadSightingGraph(id, "attribute");
} else if (type == 'add') {
$.get( "/sightings/add/" + id, function(data) {
$("#sightingsData").html(data);
});
} else {
var org = "";
if (type == 'org') org = "/<?php echo h($me['org_id']);?>"
$.get( "/sightings/listSightings/" + id + "/attribute" + org, function(data) {
$("#sightingsData").html(data);
});
}
});
</script>
<?php echo $this->Js->writeBuffer(); // Write cached scripts

View File

@ -0,0 +1,52 @@
<div>
<div id="org_id" class="hidden"><?php echo h($org_id); ?></div>
<h2>Galaxies</h2>
<table class="table table-striped table-hover table-condensed" style="display:block; overflow-y:auto;max-height:500px;">
<tr>
<th>Date</th>
<th>Organisation</th>
<th>Type</th>
<th>Source</th>
<th>Event ID</th>
<th>Attribute ID</th>
<th class="actions">Actions</th>
</tr>
<?php
foreach ($sightings as $item):
?>
<tr>
<td class="short"><?php echo date('Y-m-d H:i:s', $item['Sighting']['date_sighting']);?></td>
<td class="short">
<?php
$imgAbsolutePath = APP . WEBROOT_DIR . DS . 'img' . DS . 'orgs' . DS . h($item['Organisation']['name']) . '.png';
if (file_exists($imgAbsolutePath)):
echo $this->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;
?>
</td>
<td class="short">
<?php
echo $types[$item['Sighting']['type']];
?>
</td>
<td class="short"><?php echo h($item['Sighting']['source']);?></td>
<td class="short"><?php echo h($item['Sighting']['event_id']);?></td>
<td class="short"><?php echo h($item['Sighting']['attribute_id']);?></td>
<td class="short action-links">
<?php
if ($isSiteAdmin || ($item['Sighting']['org_id'] == $me['org_id'] && $isAclAdd)):
?>
<span class="icon-trash useCursorPointer" onClick="quickDeleteSighting('<?php echo h($item['Sighting']['id']); ?>', '<?php echo h($rawId); ?>', '<?php echo h($context); ?>');"></span>
<?php
endif;
?>
</td>
</tr>
<?php
endforeach;
?>
</table>
</div>

View File

@ -0,0 +1,24 @@
<div class="confirmation">
<?php
echo $this->Form->create('Sighting', array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => '/sightings/quickDelete/' . $id . '/' . urlencode($rawId) . '/' . $context));
?>
<legend>Remove Sighting</legend>
<div style="padding-left:5px;padding-right:5px;padding-bottom:5px;">
<p>Remove sighting (<?php echo h($id); ?>)?</p>
<table>
<tr>
<td style="vertical-align:top">
<span id="PromptYesButton" class="btn btn-primary" onClick="removeSighting('<?php echo h($id); ?>', '<?php echo h($rawId); ?>', '<?php echo h($context); ?>');">Yes</span>
</td>
<td style="width:540px;">
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="PromptNoButton" onClick="cancelPrompt(1);">No</span>
</td>
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
</div>

View File

@ -0,0 +1,150 @@
<?php
echo $this->Html->script('d3');
echo $this->Html->css('sightingstyle');
?>
<div id="graphContent" class="graphContent"></div>
<script>
var myData = "<?php echo $tsv; ?>";
var colours = {
'Sighting': 'blue',
'False-positive': 'red'
}
var margin = {
top: 20,
right: 60,
bottom: 30,
left: 25
},
width = 980 - margin.left - margin.right,
height = 300 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.count);
});
var svg = d3.select("#graphContent").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = d3.tsv.parse(myData);
color.domain(d3.keys(data[0]).filter(function(key) {
return key !== "date";
}));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var sightings = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.date,
count: +d[name]
};
})
};
});
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([
d3.min(sightings, function(c) {
return d3.min(c.values, function(v) {
return v.count;
});
}),
d3.max(sightings, function(c) {
return d3.max(c.values, function(v) {
return v.count;
});
})
]);
var legend = svg.selectAll('g')
.data(sightings)
.enter()
.append('g')
.attr('class', 'sightingsLegend');
legend.append('rect')
.attr('x', width - 20)
.attr('y', function(d, i) {
return i * 20;
})
.attr('width', 10)
.attr('height', 10)
.style('fill', function(d) {
return colours[d.name];
});
legend.append('text')
.attr('x', width - 8)
.attr('y', function(d, i) {
return (i * 20) + 9;
})
.text(function(d) {
return d.name;
});
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Count");
var sightings = svg.selectAll(".sightings")
.data(sightings)
.enter().append("g")
.attr("class", "sightings");
sightings.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return colours[d.name];
});
</script>

View File

@ -1,6 +1,5 @@
<div class="whitelist index">
<h2>Signature Whitelist</h2>
<p>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).</p>
<h2>Import Whitelist</h2>
<div class="pagination">
<ul>
<?php

View File

@ -1,6 +1,5 @@
<div class="whitelist index">
<h2>Signature Whitelist</h2>
<p>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).</p>
<div class="pagination">
<ul>
<?php

View File

@ -762,6 +762,20 @@ a.proposal_link_red:hover {
color:white;
}
.popover-legend {
border-radius: 5px 5px 0px 0px;
margin-bottom:5px;
padding-left:0px;
background-color:black;
color:white;
font-size: 21px;
line-height: 40px;
}
.popover-legend p {
padding-left:10px;
}
.legend {
display: block;
width: 100%;
@ -1672,6 +1686,21 @@ table.table.table-striped tr.deleted_row td {
transition: all 0.3s ease;
}
.sparkline {
fill: none;
stroke: #000;
stroke-width: 0.5px;
}
.sparkcircle {
fill: #f00;
stroke: none;
}
.sightings_advanced
{
width:1000px;
}
@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);}

View File

@ -0,0 +1,20 @@
.graphContent {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}

View File

@ -14,6 +14,14 @@ function deleteObject(type, action, id, event) {
});
}
function quickDeleteSighting(id, rawId, context) {
url = "/sightings/quickDelete/" + id + "/" + rawId + "/" + context;
$.get(url, function(data) {
$("#confirmation_box").fadeIn();
$("#confirmation_box").html(data);
});
}
function publishPopup(id, type) {
var action = "alert";
if (type == "publish") action = "publish";
@ -37,6 +45,8 @@ function genericPopup(url, popupTarget) {
$.get(url, function(data) {
$(popupTarget).html(data);
$(popupTarget).fadeIn();
left = ($(window).width() / 2) - ($(popupTarget).width() / 2);
$(popupTarget).css({'left': left + 'px'});
$("#gray_out").fadeIn();
});
}
@ -64,9 +74,11 @@ function editTemplateElement(type, id) {
});
}
function cancelPrompt() {
$("#confirmation_box").fadeIn();
$("#gray_out").fadeOut();
function cancelPrompt(isolated) {
if (isolated == undefined) {
$("#gray_out").fadeOut();
}
$("#confirmation_box").fadeOut();
$("#confirmation_box").empty();
}
@ -94,6 +106,34 @@ function submitDeletion(context_id, action, type, id) {
});
}
function removeSighting(id, rawid, context) {
if (context != 'attribute') {
context = 'event';
}
var formData = $('#PromptForm').serialize();
$.ajax({
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
},
data: formData,
success:function (data, textStatus) {
handleGenericAjaxResponse(data);
},
complete:function() {
$(".loading").hide();
$("#confirmation_box").fadeOut();
var org = "/" + $('#org_id').text();
updateIndex(id, 'event');
$.get( "/sightings/listSightings/" + rawid + "/" + context + org, function(data) {
$("#sightingsData").html(data);
});
},
type:"post",
cache: false,
url:"/sightings/quickDelete/" + id + "/" + rawid + "/" + context,
});
}
function toggleSetting(e, setting, id) {
e.preventDefault();
e.stopPropagation();
@ -340,7 +380,8 @@ function postActivationScripts(name, type, id, field, event) {
$(name + '_solid').hide();
}
function addSighting(attribute_id, event_id, $page) {
function addSighting(type, attribute_id, event_id, page) {
$('#Sighting_' + attribute_id + '_type').val(type);
$.ajax({
data: $('#Sighting_' + attribute_id).closest("form").serialize(),
cache: false,
@ -527,13 +568,13 @@ function toggleAllTaxonomyCheckboxes() {
}
function attributeListAnyAttributeCheckBoxesChecked() {
if ($('.select_attribute:checked').length > 0) $('.mass-select').show();
else $('.mass-select').hide();
if ($('.select_attribute:checked').length > 0) $('.mass-select').removeClass('hidden');
else $('.mass-select').addClass('hidden');
}
function attributeListAnyProposalCheckBoxesChecked() {
if ($('.select_proposal:checked').length > 0) $('.mass-proposal-select').show();
else $('.mass-proposal-select').hide();
if ($('.select_proposal:checked').length > 0) $('.mass-proposal-select').removeClass('hidden');
else $('.mass-proposal-select').addClass('hidden');
}
function taxonomyListAnyCheckBoxesChecked() {
@ -731,6 +772,7 @@ function submitPopoverForm(context_id, referer, update_context_id) {
var url = null;
var context = 'event';
var contextNamingConvention = 'Attribute';
var closePopover = true;
switch (referer) {
case 'add':
url = "/attributes/add/" + context_id;
@ -777,20 +819,38 @@ function submitPopoverForm(context_id, referer, update_context_id) {
case 'replaceAttributes':
url = "/attributes/attributeReplace/" + context_id;
break;
case 'addSighting':
url = "/sightings/add/" + context_id;
closePopover = false;
break;
}
if (url !== null) {
$.ajax({
beforeSend: function (XMLHttpRequest) {
$(".loading").show();
$("#gray_out").fadeOut();
$("#popover_form").fadeOut();
if (closePopover) {
$("#gray_out").fadeOut();
$("#popover_form").fadeOut();
}
},
data: $("#submitButton").closest("form").serialize(),
success:function (data, textStatus) {
var result = handleAjaxPopoverResponse(data, context_id, url, referer, context, contextNamingConvention);
if (closePopover) {
var result = handleAjaxPopoverResponse(data, context_id, url, referer, context, contextNamingConvention);
}
if (referer == 'addSighting') {
updateIndex(update_context_id, 'event');
$.get( "/sightings/listSightings/" + id + "/attribute", function(data) {
$("#sightingsData").html(data);
});
$('.sightingsToggle').removeClass('btn-primary');
$('.sightingsToggle').addClass('btn-inverse');
$('#sightingsListAllToggle').removeClass('btn-inverse');
$('#sightingsListAllToggle').addClass('btn-primary');
}
if (context == 'event' && (referer == 'add' || referer == 'massEdit' || referer == 'replaceAttributes')) eventUnpublish();
$(".loading").show();
$(".loading").hide();
},
type:"post",
url:url
@ -904,7 +964,10 @@ function showMessage(success, message, context) {
}
function cancelPopoverForm() {
$("#popover_form").empty();
$("#gray_out").fadeOut();
$("#popover_form").fadeOut();
$("#screenshot_box").fadeOut();
$("#confirmation_box").fadeOut();
$('#gray_out').fadeOut();
$('#popover_form').fadeOut();
}
@ -1107,6 +1170,7 @@ function getPopup(id, context, target, admin, popupType) {
$(".loading").show();
},
dataType:"html",
async: true,
cache: false,
success:function (data, textStatus) {
$(".loading").hide();
@ -1125,6 +1189,7 @@ function simplePopup(url) {
$(".loading").show();
},
dataType:"html",
async: true,
cache: false,
success:function (data, textStatus) {
$(".loading").hide();
@ -1925,7 +1990,6 @@ function simpleTabPageLast() {
if ($('#SharingGroupRoaming').is(":checked")) {
summaryservers = "any interconnected instances linked by an eligible organisation.";
} else {
console.log(servercounter);
if (servercounter == 0) {
summaryservers = "data marked with this sharing group will not be pushed.";
}
@ -2302,6 +2366,7 @@ function serverRuleUpdate() {
});
}
statusOptions.forEach(function(status) {
console.log();
if (rules[type][field][status].length > 0) {
$('#' + type + '_' + field + '_' + status).show();
var t = '';
@ -2831,7 +2896,7 @@ function checkAndSetPublishedInfo() {
$(document).keyup(function(e){
if (e.keyCode === 27) {
$("#gray_out").fadeOut();
$("#gray_out").fadeOut();
$("#popover_form").fadeOut();
$("#screenshot_box").fadeOut();
$("#confirmation_box").fadeOut();
@ -2844,3 +2909,9 @@ function closeScreenshot() {
$("#screenshot_box").fadeOut();
$("#gray_out").fadeOut();
}
function loadSightingGraph(id, scope) {
$.get( "/sightings/viewSightings/" + id + "/" + scope, function(data) {
$("#sightingsData").html(data);
});
}