Merge branch '2.4' of github.com:MISP/MISP into 2.4

pull/5560/head
iglocska 2020-04-07 13:23:25 +02:00
commit ad4074c1d6
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
42 changed files with 1800 additions and 159 deletions

View File

@ -2070,6 +2070,10 @@ installCake_RHEL ()
sudo scl enable rh-php72 'yes no|pecl install redis'
echo "extension=redis.so" |sudo tee /etc/opt/rh/rh-php72/php.d/99-redis.ini
sudo ln -s /usr/lib64/libfuzzy.so /usr/lib/libfuzzy.so
sudo scl enable rh-php72 'pecl install ssdeep'
echo "extension=ssdeep.so" |sudo tee /etc/opt/rh/rh-php72/php.d/99-ssdeep.ini
# Install gnupg extension
sudo yum install gpgme-devel -y
sudo scl enable rh-php72 'pecl install gnupg'

View File

@ -1,5 +1,5 @@
; Generated by RHash v1.3.9 on 2020-03-18 at 13:56.48
; Generated by RHash v1.3.9 on 2020-03-28 at 11:27.22
; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/
;
; 99980 13:56.48 2020-03-18 INSTALL.sh
INSTALL.sh 04A834FCD3BC9DA5282EDE8A3D2C459FBC625E46 FBCA1473FEC26AD5A6C1AE6AE3D9AF11E47E7758F30B160BC047ABE9978F4476 7281B13AA7D6B016152096D35619C2CECC7EC49F8F41CF8A3B8284335D950D35F273FA56FEA63EC5ADB3669038239C61 FA17DF3AA0CBC54D2B48AE14FB296C91C12FC6CF8E3704B8AF1B2CB2CDE9C6FAF591A2E42A38C01C299C62390868E7766EF682A6B3B556BAFC469688E8AED6E7
; 129017 11:27.22 2020-03-28 INSTALL.sh
INSTALL.sh D13A40A737C9FC7BCB6085F7557EAE47E48AF57A FBD4920A02D7811FF6280306FE1ED0CF6ADDD3707B2E0F9D1FF58F808CC92784 66A1518CCBBAC090C84748D59BE0D45CF9EB4882AF3B65CFA0E0F1CD76CE82D928A5EB16B4927A297C29BBE964B104F9 ED28FA2445A350193E6089E44E1451E34DE3C4A49643B8A8F2690488067AD05E806FA5A169044525F4686D3E5171F6A8EE65415EF5BB3DE6884BA93F9EE7BA05

View File

@ -1 +1 @@
c85dfcbc3da0b6b6331a9ef057e04d1921205d22 INSTALL.sh
d13a40a737c9fc7bcb6085f7557eae47e48af57a INSTALL.sh

View File

@ -1 +1 @@
4665b8df8c1baecda9bc5ef729033c7b2d64e72b6395e3fc260927cce394b16a INSTALL.sh
fbd4920a02d7811ff6280306fe1ed0cf6addd3707b2e0f9d1ff58f808cc92784 INSTALL.sh

View File

@ -1 +1 @@
6bc8ba92099f339152211bee3603553a8647dcd67ec9b1929cf0c489c70b4db8772d8bb31508782d82343770dac06426 INSTALL.sh
66a1518ccbbac090c84748d59be0d45cf9eb4882af3b65cfa0e0f1cd76ce82d928a5eb16b4927a297c29bbe964b104f9 INSTALL.sh

View File

@ -1 +1 @@
32793e6dcf99b32fc8271a8cdda862e60bbbd256eb24a1f6711770a931ddc552ab4dc50a7d841d5030cea43717275d8ebbc6c7c641dc8f02d11f5ea20eeef35c INSTALL.sh
ed28fa2445a350193e6089e44e1451e34de3c4a49643b8a8f2690488067ad05e806fa5a169044525f4686d3e5171f6a8ee65415ef5bb3de6884ba93f9ee7ba05 INSTALL.sh

2
PyMISP

@ -1 +1 @@
Subproject commit 64d7c9a24ad9d3a7ccc1b96fb643c235d2b9e02e
Subproject commit 5e46724646c0aa779b827678333a21a5e9eb2034

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":123}
{"major":2, "minor":4, "hotfix":124}

View File

@ -1411,7 +1411,7 @@ class AttributesController extends AppController
$event = $this->Attribute->Event->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1,
'fields' => array('id', 'orgc_id', 'user_id', 'published', 'timestamp', 'info', 'uuid')
'fields' => array('id', 'orgc_id', 'org_id', 'user_id', 'published', 'timestamp', 'info', 'uuid')
));
if (!$this->_isSiteAdmin()) {
if ($event['Event']['orgc_id'] != $this->Auth->user('org_id') || (!$this->userRole['perm_modify_org'] && !($this->userRole['perm_modify'] && $event['user_id'] == $this->Auth->user('id')))) {
@ -1477,7 +1477,23 @@ class AttributesController extends AppController
}
if ($changeInAttribute) {
if ($this->Attribute->saveMany($attributes)) {
if ($this->request->data['Attribute']['is_proposal']) { // create ShadowAttributes instead
$shadowAttributes = array();
foreach ($attributes as $attribute) {
$shadowAttribute['ShadowAttribute'] = $attribute['Attribute'];
unset($shadowAttribute['ShadowAttribute']['id']);
$shadowAttribute['ShadowAttribute']['email'] = $this->Auth->user('email');
$shadowAttribute['ShadowAttribute']['org_id'] = $this->Auth->user('org_id');
$shadowAttribute['ShadowAttribute']['event_uuid'] = $event['Event']['uuid'];
$shadowAttribute['ShadowAttribute']['event_org_id'] = $event['Event']['org_id'];
$shadowAttribute['ShadowAttribute']['old_id'] = $attribute['Attribute']['id'];
$shadowAttributes[] = $shadowAttribute;
}
$saveSuccess = $this->Attribute->ShadowAttribute->saveMany($shadowAttributes);
} else {
$saveSuccess = $this->Attribute->saveMany($attributes);
}
if ($saveSuccess) {
if (!$this->_isRest()) {
$this->Attribute->Event->insertLock($this->Auth->user(), $id);
}
@ -1662,6 +1678,31 @@ class AttributesController extends AppController
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
if (!empty($filters['uuid'])) {
if (!is_array($filters['uuid'])) {
$filters['uuid'] = array($filters['uuid']);
}
$uuid = array();
$ids = array();
foreach ($filters['uuid'] as $k => $filter) {
if ($filter[0] === '!') {
$filter = substr($filter, 1);
}
if (Validation::uuid($filter)) {
$uuid[] = $filters['uuid'][$k];
} else {
$ids[] = $filters['uuid'][$k];
}
}
if (empty($uuid)) {
unset($filters['uuid']);
} else {
$filters['uuid'] = $uuid;
}
if (!empty($ids)) {
$filters['eventid'] = $ids;
}
}
unset($filterData);
if ($filters === false) {
return $exception;

View File

@ -415,7 +415,11 @@ class EventsController extends AppController
$orgUuidArray = $this->Event->Org->find('list', array('fields' => array('Org.uuid')));
$orgArray = array_map('strtoupper', $orgArray);
// if the first character is '!', search for NOT LIKE the rest of the string (excluding the '!' itself of course)
$pieces = explode('|', $v);
if (!is_array($v)) {
$pieces = explode('|', $v);
} else {
$pieces = $v;
}
$test = array();
foreach ($pieces as $piece) {
if ($piece[0] == '!') {

View File

@ -246,7 +246,7 @@ class FeedsController extends AppController
$this->Flash->success($message);
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
} else {
$message = __('Feed could not be added. Invalid field: %s', array_keys($this->Feed->validationErrors)[0]);
$message = __('Feed could not be added. Reason: %s', json_encode($this->Feed->validationErrors));
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Feeds', 'add', false, $message, $this->response->type());
}
@ -345,7 +345,7 @@ class FeedsController extends AppController
$this->Flash->success($message);
$this->redirect(array('controller' => 'feeds', 'action' => 'index'));
} else {
$message = __('Feed could not be updated. Invalid fields: %s', implode(', ', array_keys($this->Feed->validationErrors)));
$message = __('Feed could not be updated. Reason: %s', json_encode($this->Feed->validationErrors));
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Feeds', 'add', false, $message, $this->response->type());
}

View File

@ -398,7 +398,7 @@ class ObjectsController extends AppController
$this->set('updateable_attribute', $templateData['updateable_attribute']);
$this->set('not_updateable_attribute', $templateData['not_updateable_attribute']);
if (isset($this->params['named']['revised_object'])) {
$revisedData = $this->MispObject->reviseObject($this->params['named']['revised_object'], $object);
$revisedData = $this->MispObject->reviseObject($this->params['named']['revised_object'], $object, $template);
$this->set('revised_object', $revisedData['revised_object_both']);
$object = $revisedData['object'];
}

View File

@ -638,13 +638,14 @@ class UsersController extends AppController
if (isset($this->request->data['User']['password'])) {
$this->request->data['User']['confirm_password'] = $this->request->data['User']['password'];
}
$default_publish_alert = Configure::check('MISP.default_publish_alert') ? Configure::read('MISP.default_publish_alert') : 0;
$defaults = array(
'external_auth_required' => 0,
'external_auth_key' => '',
'server_id' => 0,
'gpgkey' => '',
'certif_public' => '',
'autoalert' => 0,
'autoalert' => $default_publish_alert,
'contactalert' => 0,
'disabled' => 0,
'newsread' => 0,

View File

@ -0,0 +1,305 @@
<?php
class CsseCovidMapWidget
{
public $title = 'CSSE Covid-19 map';
public $render = 'WorldMap';
public $width = 3;
public $height = 4;
public $params = array(
'event_info' => 'World map based on the countries with infections.',
'type' => 'Type of data used for the widget (confirmed, death, recovered).',
'logarithmic' => 'Use a log10 scale for the graph (set via 0/1).'
);
public $description = 'Widget mapping the countries showing confirmed cases of COVID-19.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"logarithmic": 1
}';
public $countryCodes = array(
'Afghanistan' => 'AF',
'Albania' => 'AL',
'Algeria' => 'DZ',
'Angola' => 'AO',
'Argentina' => 'AR',
'Armenia' => 'AM',
'Australia' => 'AU',
'Austria' => 'AT',
'Azerbaijan' => 'AZ',
'Bahamas' => 'BS',
'Bangladesh' => 'BD',
'Belarus' => 'BY',
'Belgium' => 'BE',
'Belize' => 'BZ',
'Benin' => 'BJ',
'Bhutan' => 'BT',
'Bolivia' => 'BO',
'Bosnia and Herz.' => 'BA',
'Botswana' => 'BW',
'Brazil' => 'BR',
'Brunei' => 'BN',
'Bulgaria' => 'BG',
'Burkina Faso' => 'BF',
'Burundi' => 'BI',
'Cambodia' => 'KH',
'Cameroon' => 'CM',
'Canada' => 'CA',
'Central African Rep.' => 'CF',
'Chad' => 'TD',
'Chile' => 'CL',
'China' => 'CN',
'Colombia' => 'CO',
'Congo' => 'CG',
'Costa Rica' => 'CR',
'Croatia' => 'HR',
'Cuba' => 'CU',
'Cyprus' => 'CY',
'Czech Rep.' => 'CZ',
'Côte d\'Ivoire' => 'CI',
'Dem. Rep. Congo' => 'CD',
'Dem. Rep. Korea' => 'KP',
'Denmark' => 'DK',
'Djibouti' => 'DJ',
'Dominican Rep.' => 'DO',
'Ecuador' => 'EC',
'Egypt' => 'EG',
'El Salvador' => 'SV',
'Eq. Guinea' => 'GQ',
'Eritrea' => 'ER',
'Estonia' => 'EE',
'Ethiopia' => 'ET',
'Falkland Is.' => 'FK',
'Fiji' => 'FJ',
'Finland' => 'FI',
'Fr. S. Antarctic Lands' => 'TF',
'France' => 'FR',
'Gabon' => 'GA',
'Gambia' => 'GM',
'Georgia' => 'GE',
'Germany' => 'DE',
'Ghana' => 'GH',
'Greece' => 'GR',
'Greenland' => 'GL',
'Guatemala' => 'GT',
'Guinea' => 'GN',
'Guinea-Bissau' => 'GW',
'Guyana' => 'GY',
'Haiti' => 'HT',
'Honduras' => 'HN',
'Hungary' => 'HU',
'Iceland' => 'IS',
'India' => 'IN',
'Indonesia' => 'ID',
'Iran' => 'IR',
'Iraq' => 'IQ',
'Ireland' => 'IE',
'Israel' => 'IL',
'Italy' => 'IT',
'Jamaica' => 'JM',
'Japan' => 'JP',
'Jordan' => 'JO',
'Kazakhstan' => 'KZ',
'Kenya' => 'KE',
'Korea' => 'KR',
'Kuwait' => 'KW',
'Kyrgyzstan' => 'KG',
'Lao PDR' => 'LA',
'Latvia' => 'LV',
'Lebanon' => 'LB',
'Lesotho' => 'LS',
'Liberia' => 'LR',
'Libya' => 'LY',
'Lithuania' => 'LT',
'Luxembourg' => 'LU',
'Macedonia' => 'MK',
'Madagascar' => 'MG',
'Mainland China' => 'CN',
'Malawi' => 'MW',
'Malaysia' => 'MY',
'Mali' => 'ML',
'Mauritania' => 'MR',
'Mexico' => 'MX',
'Moldova' => 'MD',
'Mongolia' => 'MN',
'Montenegro' => 'ME',
'Morocco' => 'MA',
'Mozamb' => 'MZ',
'Myanmar' => 'MM',
'Namibia' => 'NA',
'Nepal' => 'NP',
'Netherlands' => 'NL',
'New Caledonia' => 'NC',
'New Zealand' => 'NZ',
'Nicaragua' => 'NI',
'Niger' => 'NE',
'Nigeria' => 'NG',
'Norway' => 'NO',
'Oman' => 'OM',
'Pakistan' => 'PK',
'Palestine' => 'PS',
'Panama' => 'PA',
'Papua New Guinea' => 'PG',
'Paraguay' => 'PY',
'Peru' => 'PE',
'Philippines' => 'PH',
'Poland' => 'PL',
'Portugal' => 'PT',
'Puerto Rico' => 'PR',
'Qatar' => 'QA',
'Romania' => 'RO',
'Russia' => 'RU',
'Rwanda' => 'RW',
'S. Sudan' => 'SS',
'Saudi Arabia' => 'SA',
'Senegal' => 'SN',
'Serbia' => 'RS',
'Sierra Leone' => 'SL',
'Slovakia' => 'SK',
'Slovenia' => 'SI',
'Solomon Is.' => 'SB',
'Somalia' => 'SO',
'South Africa' => 'ZA',
'Spain' => 'ES',
'Sri Lanka' => 'LK',
'Sudan' => 'SD',
'Suriname' => 'SR',
'Swaziland' => 'SZ',
'Sweden' => 'SE',
'Switzerland' => 'CH',
'Syria' => 'SY',
'Taiwan' => 'TW',
'Tajikistan' => 'TJ',
'Tanzania' => 'TZ',
'Thailand' => 'TH',
'Timor-Leste' => 'TL',
'Togo' => 'TG',
'Trinidad and Tobago' => 'TT',
'Tunisia' => 'TN',
'Turkey' => 'TR',
'Turkmenistan' => 'TM',
'Uganda' => 'UG',
'Ukraine' => 'UA',
'United Arab Emirates' => 'AE',
'United Kingdom' => 'GB',
'United States' => 'US',
'Uruguay' => 'UY',
'Uzbekistan' => 'UZ',
'Vanuatu' => 'VU',
'Venezuela' => 'VE',
'Vietnam' => 'VN',
'W. Sahara' => 'EH',
'Yemen' => 'YE',
'Zambia' => 'ZM',
'Zimbabwe' => 'ZW'
);
public $countryCodesReversed = array();
public function handler($user, $options = array())
{
$this->countryCodesReversed = array_flip($this->countryCodes);
$this->Event = ClassRegistry::init('Event');
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'limit' => 1,
'page' => 1
);
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
$data = $this->__handleEvents($events, $options);
arsort($data);
}
$data = array('data' => $data);
if (!empty($options['type']) && $options['type'] === 'mortality') {
$data['output_decorator'] = 'percentage';
}
if (!empty($options['logarithmic'])) {
$data['logarithmic'] = array();
foreach ($data['data'] as $k => $v) {
if ($v == 0) {
$value = 0;
} else if ($v <= 1) {
$value = 0.2;
} else {
$value = log10($v);
}
$data['logarithmic'][$k] = $value;
}
}
$data['scope'] = Inflector::humanize($options['type']);
$data['colour_scale'] = json_encode(array('#F08080', '#8B0000'), true);
return $data;
}
private function __handleEvents($events, $options)
{
$data = array();
if (!empty($events)) {
foreach ($events as $event) {
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options);
}
}
}
return $data;
}
private function __handleObjects($data, $objects, $options)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object);
$data = $this->__rearrangeResults($data, $temp, $options);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
$data[$k] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options)
{
$country = $temp['country-region'];
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country] = (empty($data[$country]) ? $temp[$type] : ($data[$country] + $temp[$type]));
}
return $data;
}
private function __interpretObject($object)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] === 'country-region') {
if (!empty($this->countryCodes[$attribute['value']])) {
$temp[$attribute['object_relation']] = $this->countryCodes[$attribute['value']];
} elseif (isset($this->countryCodesReversed[$attribute['value']])) {
$temp[$attribute['object_relation']] = $attribute['value'];
} else {
$temp[$attribute['object_relation']] = 'XX';
}
} else {
$attribute['value'] = intval($attribute['value']);
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
}
return $temp;
}
}

View File

@ -0,0 +1,201 @@
<?php
class CsseCovidTrendsWidget
{
public $title = 'CSSE Covid-19 trends';
public $render = 'MultiLineChart';
public $width = 4;
public $height = 5;
public $params = array(
'event_info' => 'Substring included in the info field of relevant CSSE COVID-19 events.',
'type' => 'Type of data used for the widget - confirmed (default), death, recovered, mortality.',
'insight' => 'Insight type - raw (default), growth, percent.',
'countries' => 'List of countries to be included (using the names used by the reports, such as Belgium, US, Germany).',
'timeframe' => 'Timeframe for events taken into account in days (going back from now, using the date field, default 10).'
);
public $description = 'Widget showing line charts for the evolution of the various case types.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"insight": "growth",
"countries": ["Luxembourg", "Germany", "Belgium", "France"],
"timeframe": 20
}';
//public $cacheLifetime = 600;
public $autoRefreshDelay = false;
private $__countries = array();
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
if (!isset($options['insight']) || !isset($this->__insightFunctions[$options['insight']])) {
$options['Insight'] = 'calculate_growth_rate';
}
if (empty($options['timeframe'])) {
$options['timeframe'] = 10;
}
if (empty($options['countries'])) {
$options['countries'] = array("Luxembourg", "Germany", "Belgium", "France");
}
if (empty($options['insight'])) {
$options['insight'] = 'raw';
}
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'date' => (empty($options['timeframe']) ? 10 : $options['timeframe']) . 'd'
);
$eventIds = $this->Event->filterEventIds($user, $params);
$eventIds = array_reverse(array_values($eventIds));
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$previous = false;
foreach ($eventIds as $eventId) {
$params = array('eventid' => $eventId);
$event = $this->Event->fetchEvent($user, $params);
if (!empty($event)) {
$data[$event[0]['Event']['date']] = $this->__handleEvent($event[0], $options, $previous);
}
$previous = $data[$event[0]['Event']['date']];
}
}
$startDate = date('Y-m-d', strtotime('-' . intval($options['timeframe']) . ' days'));
//$data = call_user_func_array((array($this, $this->__insightFunctions[$options['Insight']]), array($startDate));
$data = array('data' => $data);
$data['insight'] = empty($options['insight']) ? 'raw' : $options['insight'];
foreach ($data['data'] as $date => $day) {
$data['data'][$date]['date'] = $date;
foreach ($this->__countries as $country => $temp) {
if (empty($data['data'][$date][$country][$data['insight']])) {
$data['data'][$date][$country][$data['insight']] = 0;
}
}
}
$data['data'] = array_values($data['data']);
$formulaData = array(
'insight' => array(
'raw' => '',
'growth' => 'daily increase in ',
'percent' => 'percentage wise daily increase in '
),
'type' => array(
'confirmed' => 'confirmed cases',
'death' => 'mortalities',
'recovered' => 'recoveries',
'mortality' => 'mortality rate'
)
);
$data['formula'] = sprintf(
'%s%s',
(isset($options['insight']) && !empty($formulaData[$options['insight']])) ?
$formulaData['insight'][$options['insight']] :
$formulaData['insight']['raw'],
(isset($options['type']) && !empty($formulaData['type'][$options['type']])) ?
$formulaData['type'][$options['type']] :
$formulaData['type']['confirmed']
);
$data['formula'] = ucfirst($data['formula']);
foreach ($data['data'] as &$day) {
foreach ($day as $key => &$countryData) {
if ($key !== 'date') {
$countryData = $countryData[$options['insight']];
}
}
}
return $data;
}
private function __handleEvent($event, $options, $previous)
{
$data = array();
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options, $previous);
}
$data['date'] = $event['Event']['date'];
return $data;
}
private function __handleObjects($data, $objects, $options, $previous)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object, $previous);
$data = $this->__rearrangeResults($data, $temp, $options, $previous);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
$data[$k]['mortality'] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
if (!empty($options['insight']) && $options['insight'] !== 'raw') {
if ($options['insight'] == 'growth') {
foreach ($data as $k => &$countryData) {
foreach ($countryData as $type => &$value) {
if (empty($previous[$k][$type])) {
$previous[$k][$type] = 0;
}
$data[$k]['growth'] = $data[$k][$type] - $previous[$k][$type];
}
}
} else if ($options['insight'] == 'percent') {
foreach ($data as $k => &$countryData) {
foreach ($countryData as $type => &$value) {
if (empty($previous[$k][$type])) {
$previous[$k][$type] = $data[$k][$type];
}
$data[$k]['percent'] = ($data[$k][$type] - $previous[$k][$type]) / $previous[$k][$type];
}
}
}
} else {
foreach ($data as $k => &$countryData) {
$data[$k]['raw'] = $data[$k][$options['type']];
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options, $previous)
{
$country = $temp['country-region'];
if (!in_array($country, $options['countries'])) {
return $data;
}
$this->__countries[$country] = 1;
if ($options['type'] === 'mortality') {
foreach (array('confirmed', 'death') as $type) {
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
} else {
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
return $data;
}
private function __interpretObject($object, $previous)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] !== 'country-region') {
$attribute['value'] = intval($attribute['value']);
}
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
return $temp;
}
}

View File

@ -0,0 +1,182 @@
<?php
class CsseCovidWidget
{
public $title = 'CSSE Covid-19 data';
public $render = 'BarChart';
public $width = 3;
public $height = 4;
public $params = array(
'event_info' => 'Substring included in the info field of relevant CSSE COVID-19 events.',
'type' => 'Type of data used for the widget (confirmed, death, recovered, mortality).',
'logarithmic' => 'Use a log10 scale for the graph (set via 0/1).',
'relative' => 'Take the country\'s population size into account (count / 10M)'
);
public $description = 'Widget visualising the countries ranked by highest count in the chosen category.';
public $placeholder =
'{
"event_info": "%CSSE COVID-19 daily report%",
"type": "confirmed",
"logarithmic": 1,
"relative": 0
}';
public $__nameReplacements = array(
'US' => 'United States',
'Cote d\'Ivoire' => 'Ivory Coast',
'Holy See' => 'Vatican',
'Congo (Kinshasa)' => 'Democratic Republic of Congo',
'Taiwan*' => 'Taiwan',
'Korea, South' => 'South Korea'
);
private $__populationData = array();
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
$event_info_condition = empty($options['event_info']) ? '%CSSE COVID-19 daily report%' : $options['event_info'];
$params = array(
'eventinfo' => $event_info_condition,
'order' => 'date desc',
'limit' => 1,
'page' => 1
);
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';
}
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
$data = $this->__handleEvents($events, $options);
arsort($data);
}
$data = array('data' => $data);
if (!empty($options['type']) && $options['type'] === 'mortality') {
$data['output_decorator'] = 'percentage';
}
if ($options['type'] !== 'mortality' && !empty($options['relative'])) {
$this->__getPopulationData();
if (!empty($this->__populationData)) {
foreach ($data['data'] as $country => $value) {
if (isset($this->__nameReplacements[$country])) {
$alias = $this->__nameReplacements[$country];
} else {
$alias = $country;
}
if (empty($this->__populationData[$alias])) {
unset($data['data'][$country]);
} else {
$pre = $data['data'][$country];
$data['data'][$country] = round(10000000 * $data['data'][$country] / $this->__populationData[$alias]);
}
}
}
arsort($data['data']);
}
if (!empty($options['logarithmic'])) {
$data['logarithmic'] = array();
foreach ($data['data'] as $k => $v) {
if ($v == 0) {
$value = 0;
} else if ($v <= 1) {
$value = 0.2;
} else {
$value = log10($v);
}
$data['logarithmic'][$k] = $value;
}
}
return $data;
}
private function __getPopulationData()
{
$this->Galaxy = ClassRegistry::init('Galaxy');
$galaxy = $this->Galaxy->find('first', array(
'recursive' => -1,
'contain' => array('GalaxyCluster' => array('GalaxyElement')),
'conditions' => array('Galaxy.name' => 'Country')
));
if (empty($galaxy)) {
return false;
}
foreach ($galaxy['GalaxyCluster'] as $cluster) {
foreach ($cluster['GalaxyElement'] as $element) {
if ($element['key'] === 'Population') {
$this->__populationData[$cluster['description']] = $element['value'];
}
}
}
return true;
}
private function __handleEvents($events, $options)
{
$data = array();
if (!empty($events)) {
foreach ($events as $event) {
if (!empty($event['Object'])) {
$data = $this->__handleObjects($data, $event['Object'], $options);
}
}
}
return $data;
}
private function __handleObjects($data, $objects, $options)
{
foreach ($objects as $object) {
if ($object['name'] === 'covid19-csse-daily-report') {
$temp = $this->__interpretObject($object);
$data = $this->__rearrangeResults($data, $temp, $options);
}
}
if ($options['type'] === 'mortality') {
foreach ($data as $k => $v) {
if (!isset($v['death']) || empty($v['confirmed'])) {
unset($data[$k]);
continue;
}
$data[$k] = round(100 * (empty($v['death']) ? 0 : $v['death']) / $v['confirmed'], 2);
}
}
return $data;
}
private function __rearrangeResults($data, $temp, $options)
{
$country = $temp['country-region'];
if ($options['type'] === 'mortality') {
foreach (array('confirmed', 'death') as $type) {
if (!empty($temp[$type])) {
$data[$country][$type] = (empty($data[$country][$type]) ? $temp[$type] : ($data[$country][$type] + $temp[$type]));
}
}
} else {
$type = $options['type'];
if (!empty($temp[$type])) {
$data[$country] = (empty($data[$country]) ? $temp[$type] : ($data[$country] + $temp[$type]));
}
}
return $data;
}
private function __interpretObject($object)
{
$temp = array();
$validFields = array('country-region', 'confirmed', 'death', 'recovered');
foreach ($object['Attribute'] as $attribute) {
if (in_array($attribute['object_relation'], $validFields)) {
if ($attribute['object_relation'] !== 'country-region') {
$attribute['value'] = intval($attribute['value']);
}
$temp[$attribute['object_relation']] = $attribute['value'];
}
}
return $temp;
}
}

View File

@ -9,11 +9,13 @@ class TrendingTagsWidget
public $params = array(
'time_window' => 'The time window, going back in seconds, that should be included.',
'exclude' => 'List of substrings to exclude tags by - for example "sofacy" would exclude any tag containing sofacy.',
'include' => 'List of substrings to include tags by - for example "sofacy" would include any tag containing sofacy.'
'include' => 'List of substrings to include tags by - for example "sofacy" would include any tag containing sofacy.',
'threshold' => 'Limits the number of displayed tags. Default: 10'
);
public $placeholder =
'{
"time_window": "86400",
"threshold": 15,
"exclude": ["tlp:", "pap:"],
"include": ["misp-galaxy:", "my-internal-taxonomy"]
}';
@ -26,6 +28,7 @@ class TrendingTagsWidget
'metadata' => 1,
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window'])
);
$threshold = empty($options['threshold']) ? 10 : $options['threshold'];
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$events = array();
@ -34,8 +37,6 @@ class TrendingTagsWidget
}
$tags = array();
$tagColours = array();
$rules['exclusions'] = empty($options['exclude']) ? array() : $options['exclude'];
$rules['inclusions'] = empty($options['exclude']) ? array() : $options['exclude'];
foreach ($events as $event) {
foreach ($event['EventTag'] as $et) {
if ($this->checkTag($options, $et['Tag']['name'])) {
@ -49,7 +50,7 @@ class TrendingTagsWidget
}
}
arsort($tags);
$data['data'] = array_slice($tags, 0, 10);
$data['data'] = array_slice($tags, 0, $threshold);
$data['colours'] = $tagColours;
return $data;
}

View File

@ -19,6 +19,8 @@ class Stix2Export extends StixExport
$scriptFile = $this->__scripts_dir . $this->__script_name;
$filename = $this->__scripts_dir . 'tmp/' . $filename;
$my_server = ClassRegistry::init('Server');
return shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . $this->__end_of_cmd);
$result = shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . $this->__end_of_cmd);
$result = preg_split("/\r\n|\n|\r/", trim($result));
return end($result);
}
}

@ -1 +1 @@
Subproject commit d2e1681eb8ec75e6c2819fa113834843fed6995a
Subproject commit 5ccb12354dfc08ca1b3e0a430e8668bf1610b5d3

View File

@ -4426,7 +4426,6 @@ class Attribute extends AppModel
'event_timestamp' => array('function' => 'set_filter_timestamp', 'pop' => true),
'publish_timestamp' => array('function' => 'set_filter_timestamp'),
'org' => array('function' => 'set_filter_org'),
'uuid' => array('function' => 'set_filter_uuid'),
'published' => array('function' => 'set_filter_published')
),
'Object' => array(
@ -4487,7 +4486,6 @@ class Attribute extends AppModel
$subqueryElements = $this->Event->harvestSubqueryElements($filters);
$filters = $this->Event->addFiltersFromSubqueryElements($filters, $subqueryElements);
$conditions = $this->buildFilterConditions($user, $filters);
$params = array(
'conditions' => $conditions,
@ -4617,4 +4615,28 @@ class Attribute extends AppModel
}
return true;
}
public function set_filter_uuid(&$params, $conditions, $options)
{
if (!empty($params['uuid'])) {
$params['uuid'] = $this->convert_filters($params['uuid']);
if (!empty($params['uuid']['OR'])) {
$conditions['AND'][] = array(
'OR' => array(
'Event.uuid' => $params['uuid']['OR'],
'Attribute.uuid' => $params['uuid']['OR']
)
);
}
if (!empty($params['uuid']['NOT'])) {
$conditions['AND'][] = array(
'NOT' => array(
'Event.uuid' => $params['uuid']['NOT'],
'Attribute.uuid' => $params['uuid']['NOT']
)
);
}
}
return $conditions;
}
}

View File

@ -42,7 +42,7 @@ class Bruteforce extends AppModel
if ($dataSource == 'Database/Mysql') {
$sql = 'DELETE FROM bruteforces WHERE `expire` <= "' . $expire . '";';
} elseif ($dataSource == 'Database/Postgres') {
$sql = 'DELETE FROM bruteforces WHERE expire <= "' . $expire . '";';
$sql = 'DELETE FROM bruteforces WHERE expire <= \'' . $expire . '\';';
}
$this->query($sql);
}

View File

@ -1667,7 +1667,6 @@ class Event extends AppModel
'object_relation' => array('function' => 'set_filter_simple_attribute'),
'tags' => array('function' => 'set_filter_tags', 'pop' => true),
'ignore' => array('function' => 'set_filter_ignore'),
'uuid' => array('function' => 'set_filter_uuid'),
'deleted' => array('function' => 'set_filter_deleted'),
'to_ids' => array('function' => 'set_filter_to_ids'),
'comment' => array('function' => 'set_filter_comment')
@ -1707,7 +1706,6 @@ class Event extends AppModel
}
}
}
$fields = array('Event.id');
if (!empty($params['include_attribute_count'])) {
$fields[] = 'Event.attribute_count';
@ -2582,17 +2580,41 @@ class Event extends AppModel
}
return $conditions;
}
public function set_filter_uuid(&$params, $conditions, $options)
{
if (!empty($params['uuid'])) {
$params['uuid'] = $this->convert_filters($params['uuid']);
if (!empty($options['scope']) && $options['scope'] === 'Event') {
$conditions = $this->generic_add_filter($conditions, $params['uuid'], 'Event.uuid');
}
if (!empty($options['scope']) && $options['scope'] === 'Attribute') {
$conditions = $this->generic_add_filter($conditions, $params['uuid'], 'Attribute.uuid');
if ($options['scope'] === 'Event') {
if (!empty($params['uuid'])) {
$params['uuid'] = $this->convert_filters($params['uuid']);
if (!empty($params['uuid']['OR'])) {
$subQueryOptions = array(
'conditions' => array('Attribute.uuid' => $params['uuid']['OR']),
'fields' => array('event_id')
);
$attributeSubquery = $this->subQueryGenerator($this->Attribute, $subQueryOptions, 'Event.id');
$conditions['AND'][] = array(
'OR' => array(
'Event.uuid' => $params['uuid']['OR'],
$attributeSubquery
)
);
}
if (!empty($params['uuid']['NOT'])) {
$subQueryOptions = array(
'conditions' => array('Attribute.uuid' => $params['uuid']['NOT']),
'fields' => array('event_id')
);
$attributeSubquery = $this->subQueryGenerator($this->Attribute, $subQueryOptions, 'Event.id');
$conditions['AND'][] = array(
'NOT' => array(
'Event.uuid' => $params['uuid']['NOT'],
$attributeSubquery
)
);
}
}
} else {
$conditions = $this->{$options['scope']}->set_filter_uuid($params, $conditions, $options);
}
return $conditions;
}
@ -3078,6 +3100,15 @@ class Event extends AppModel
}
$body .= $bodyTempOther; // append the 'other' attribute types to the bottom.
$body .= '==============================================' . "\n";
$body .= sprintf(
"You receive this e-mail because the e-mail address %s is set to receive publish alerts on the MISP instance at %s.%s%s",
$user['email'],
(empty(Configure::read('MISP.external_baseurl')) ? Configure::read('MISP.baseurl') : Configure::read('MISP.external_baseurl')),
PHP_EOL,
PHP_EOL
);
$body .= "If you would like to unsubscribe from receiving such alert e-mails, simply\ndisable publish alerts via " . $this->__getAnnounceBaseurl() . '/users/edit' . PHP_EOL;
$body .= '==============================================' . "\n";
return $body;
}

View File

@ -31,6 +31,10 @@ class Feed extends AppModel
'event_id' => array(
'rule' => array('numeric'),
'message' => 'Please enter a numeric event ID or leave this field blank.',
),
'input_source' => array(
'rule' => 'validateInputSource',
'message' => ''
)
);
@ -47,6 +51,27 @@ class Feed extends AppModel
)
);
public function validateInputSource($fields)
{
if (!empty($this->data['Feed']['input_source'])) {
$localAllowed = empty(Configure::read('Security.disable_local_feed_access'));
$validOptions = array('network');
if ($localAllowed) {
$validOptions[] = 'local';
}
if (!in_array($this->data['Feed']['input_source'], $validOptions)) {
return __(
'Invalid input source. The only valid options are %s. %s',
implode(', ', $validOptions),
(!$localAllowed && $this->data['Feed']['input_source'] === 'local') ?
__('Security.disable_local_feed_access is currently enabled, local feeds are thereby not allowed.') :
''
);
}
}
return true;
}
public function urlOrExistingFilepath($fields)
{
if ($this->isFeedLocal($this->data)) {
@ -1162,7 +1187,7 @@ class Feed extends AppModel
'recursive' => -1,
'fields' => array('id', 'url', 'name'),
'contain' => array('RemoteOrg' => array('fields' => array('RemoteOrg.id', 'RemoteOrg.name'))),
'conditions' => array('Server.caching_enabled')
'conditions' => array('Server.caching_enabled' => 1)
));
foreach ($servers as $k => $server) {
if (!$redis->exists('misp:server_cache:' . $server['Server']['id'])) {

View File

@ -326,7 +326,6 @@ class Log extends AppModel
$elasticSearchClient = $this->getElasticSearchTool();
$elasticSearchClient->pushDocument($logIndex, "log", $data);
}
if (Configure::read('Security.syslog')) {
// write to syslogd as well
$syslog = new SysLog();
@ -341,8 +340,17 @@ class Log extends AppModel
}
$entry = $data['Log']['action'];
if (!empty($data['Log']['title'])) {
$entry .= sprintf(
' -- %s',
$data['Log']['title']
);
}
if (!empty($data['Log']['description'])) {
$entry .= sprintf(' -- %s', $data['Log']['description']);
$entry .= sprintf(
' -- %s',
$data['Log']['description']
);
}
$syslog->write($action, $entry);
}

View File

@ -1234,7 +1234,7 @@ class MispObject extends AppModel
return $toReturn;
}
public function reviseObject($revised_object, $object) {
public function reviseObject($revised_object, $object, $template) {
$revised_object = json_decode(base64_decode($revised_object), true);
$revised_object_both = array('mergeable' => array(), 'notMergeable' => array());

View File

@ -512,7 +512,7 @@ class Server extends AppModel
'description' => __('Enables the use of MISP\'s background processing.'),
'value' => '',
'errorMessage' => '',
'test' => 'testBool',
'test' => 'testBoolTrue',
'type' => 'boolean',
),
'attachments_dir' => array(
@ -642,6 +642,15 @@ class Server extends AppModel
'type' => 'numeric',
'optionsSource' => 'TagCollections',
),
'default_publish_alert' => array(
'level' => 0,
'description' => __('The default setting for publish alerts when creating users.'),
'value' => true,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => true
),
'tagging' => array(
'level' => 1,
'description' => __('Enable the tagging feature of MISP. This is highly recommended.'),
@ -1304,6 +1313,16 @@ class Server extends AppModel
'type' => 'boolean',
'null' => true
),
'disable_local_feed_access' => array(
'level' => 0,
'description' => __('Disabling this setting will allow the creation/modification of local feeds (as opposed to network feeds). Enabling this setting will restrict feed sources to be network based only. When disabled, keep in mind that a malicious site administrator could get access to any arbitrary file on the system that the apache user has access to. Make sure that proper safe-guards are in place. This setting can only be modified via the CLI.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
'null' => true,
'cli_only' => 1
),
'allow_unsafe_apikey_named_param' => array(
'level' => 0,
'description' => __('Allows passing the API key via the named url parameter "apikey" - highly recommended not to enable this, but if you have some dodgy legacy tools that cannot pass the authorization header it can work as a workaround. Again, only use this as a last resort.'),
@ -2645,6 +2664,23 @@ class Server extends AppModel
return $final;
}
private function __orgRuleDowngrade($HttpSocket, $request, $server, $filter_rules)
{
$uri = $server['Server']['url'] . '/servers/getVersion';
try {
$version_response = $HttpSocket->get($uri, false, $request);
$body = $version_response->body;
$version_response = json_decode($body, true);
$version = $version_response['version'];
} catch (Exception $e) {
return $e->getMessage();
}
$version = explode('.', $version);
if ($version[0] <= 2 && $version[1] <= 4 && $version[0] <= 123) {
$filter_rules['org'] = implode('|', $filter_rules['org']);
}
return $filter_rules;
}
// Get an array of event_ids that are present on the remote server
public function getEventIdsFromServer($server, $all = false, $HttpSocket=null, $force_uuid=false, $ignoreFilterRules = false, $scope = 'events')
@ -2657,6 +2693,9 @@ class Server extends AppModel
}
$HttpSocket = $this->setupHttpSocket($server, $HttpSocket);
$request = $this->setupSyncRequest($server);
if (!empty($filter_rules['org'])) {
$filter_rules = $this->__orgRuleDowngrade($HttpSocket, $request, $server, $filter_rules);
}
$uri = $url . '/events/index';
$filter_rules['minimal'] = 1;
$filter_rules['published'] = 1;
@ -2747,6 +2786,7 @@ class Server extends AppModel
} catch (SocketException $e) {
return $e->getMessage();
}
// error, so return error message, since that is handled and everything is expecting an array
return "Error: got response code " . $response->code;
}
@ -3506,6 +3546,21 @@ class Server extends AppModel
return true;
}
public function testBoolTrue($value, $errorMessage = false)
{
if ($this->testBool($value, $errorMessage) !== true) {
return $this->testBool($value, $errorMessage);
}
if ($value === false) {
if ($errorMessage) {
return $errorMessage;
}
return 'It is highly recommended that this setting is enabled. Make sure you understand the impact of having this setting turned off.';
} else {
return true;
}
}
public function testBoolFalse($value, $errorMessage = false)
{
if ($this->testBool($value, $errorMessage) !== true) {
@ -4474,7 +4529,10 @@ class Server extends AppModel
if (isset($field['error_type'])) {
$length = false;
if (in_array($field['error_type'], array('missing_column', 'column_different'))) {
if ($field['expected']['data_type'] === 'int') {
preg_match('/([a-z]+)(?:\((?<dw>[0-9,]+)\))?\s*([a-z]+)?/i', $field['expected']['column_type'], $displayWidthMatches);
if (isset($displayWidthMatches['dw'])) {
$length = $displayWidthMatches[2];
} elseif ($field['expected']['data_type'] === 'int') {
$length = 11;
} elseif ($field['expected']['data_type'] === 'tinyint') {
$length = 1;
@ -4580,6 +4638,7 @@ class Server extends AppModel
'numeric_precision',
// 'datetime_precision', -- Only available on MySQL 5.6+
'collation_name',
'column_type',
'column_default'
)
){

View File

@ -122,6 +122,7 @@
$('#AttributeCategory').change(function() {
formCategoryChanged('Attribute');
$('#AttributeType').chosen('destroy').chosen();
if ($(this).val() === 'Internal reference') {
$("#AttributeDistribution").val('0');
checkSharingGroup('Attribute');
@ -166,6 +167,16 @@
}
}
});
<?php if (!$ajax): ?>
$('#AttributeType').chosen();
$('#AttributeCategory').chosen();
<?php else: ?>
$('#genericModal').on('shown', function() {
$('#AttributeType').chosen();
$('#AttributeCategory').chosen();
})
<?php endif; ?>
});
</script>
<?php echo $this->element('form_seen_input'); ?>

View File

@ -33,6 +33,11 @@
'label' => __('For Intrusion Detection System'),
'selected' => 2,
));
echo $this->Form->input('is_proposal', array(
'type' => 'checkbox',
'label' => __('Create proposals'),
'checked' => true
));
?>
<div class="input clear"></div>

View File

@ -15,13 +15,13 @@ if (typeof d3 === "undefined") { // load d3.js once. This is necessary as d3.js
init<?= $seed ?>();
})
} else { // d3.js is already loaded or is loading
runInitWhenReady()
runInitWhenReady<?= $seed ?>()
}
function runInitWhenReady() {
function runInitWhenReady<?= $seed ?>() {
if (d3.version === undefined) { // d3.js not loaded yet
setTimeout(function() {
runInitWhenReady();
runInitWhenReady<?= $seed ?>();
}, 50);
} else {
init<?= $seed ?>();
@ -30,7 +30,6 @@ function runInitWhenReady() {
function init<?= $seed ?>() { // variables and functions have their own scope (no override)
'use strict';
/**
*
* Data expected format: Array({
@ -455,9 +454,6 @@ function init<?= $seed ?>() { // variables and functions have their own scope (n
.on('mouseover', function(d) {
tooltipDate(true, this, d);
})
.on('mouseout', function() {
tooltipDate(false);
})
.on('click', function(d) {
handleMarkerClick(d);
})
@ -516,48 +512,30 @@ function init<?= $seed ?>() { // variables and functions have their own scope (n
}
function tooltipDate(show, d3Element, datum) {
var tooltip = _toggleTooltip(show, d3Element);
if (show) {
tooltip.html(_generate_tooltip(datum));
var tooltipBR = tooltip.node().getBoundingClientRect();
var tooltipHeight = tooltipBR.height;
var tooltipWidth = tooltipBR.width;
var tooltipcx = parseInt(d3.select(d3Element).attr('cx'));
var dcx = 17;
// Flip tooltip position if necessary
if (width < options.margin.right + tooltipcx - dcx + tooltipWidth) {
var tooltipLeft = parseInt(tooltip.style('left').split('px')[0]);
tooltip.style('left', (tooltipLeft - (dcx + tooltipWidth + 15)) + 'px')
}
var tooltipTop = parseInt(tooltip.style('top').split('px')[0]);
tooltip.style('top', (tooltipTop - tooltipHeight/2) + 'px')
}
}
function _toggleTooltip(show, d3Element) {
if (show) {
tooltip_container
.style('display', 'block')
.style('left', (d3.event.pageX + 17) + 'px')
.style('top', (d3.event.pageY) + 'px')
.transition()
.duration(options.animation_short_duration)
.delay(options.animation_short_duration/2)
.style('opacity', '0.7');
} else {
tooltip_container.transition()
.duration(options.animation_short_duration)
.style('opacity', 0)
.delay(options.animation_short_duration)
.style('display', 'none');
}
return tooltip_container;
var $d3Element = $(d3Element);
$d3Element.tooltip({
html: true,
container: 'body',
title: _generate_tooltip(datum)
}).tooltip('show')
}
function _generate_tooltip(datum) {
var formated_date = d3.time.format(options.time_format)(datum.date);
var html = $('<p></p>').text(datum.name).html() + ' (' + formated_date + ', <strong>' + $('<p></p>').text(datum.count).html() + '</strong>) ';
return html;
var formated_x = options.abscissa_linear ? datum.index : d3.time.format(options.time_format)(datum.date);
return $('<div></div>').append(
$('<h6></h6>').text(formated_x).css({'margin': 0}),
$('<h6></h6>').append(
$('<span></span>').text(datum.name).css({'margin-right': '1em'}).prepend(
$('<svg height="10px" width="15px"></svg>').append($('<circle></circle>')
.attr('cx', 5)
.attr('cy', 5)
.attr('r', 5)
.css('fill', colors(datum.name))
)
),
$('<span></span>').text(datum.count)
).css({'margin': 0})
)[0].outerHTML
}
function handleMarkerClick(datum) {
@ -610,7 +588,7 @@ function init<?= $seed ?>() { // variables and functions have their own scope (n
var left = (overlayLeftBCR.width - overlayRightBCR.width > 0 ?
overlayLeftBCR.left + overlayLeftBCR.width/2 :
overlayRightBCR.left + overlayRightBCR.width/2) - tooltipBCR.width / 2;
var top = overlayLeftBCR.top + 30;
var top = overlayLeftBCR.top + window.scrollY + 30;
tooltipPickedNodes
.style('left', left + 'px')

View File

@ -85,7 +85,8 @@
);
$rows = '';
foreach ($dbSchemaDiagnostics as $tableName => $tableDiagnostic) {
$rows .= sprintf('<tr data-tablename="%s">', $tableName);
$tableContainsCritical = array_filter(Hash::extract($tableDiagnostic, '{n}.is_critical'));
$rows .= sprintf('<tr class="%s" data-tablename="%s">', $tableContainsCritical ? '' : 'noncritical', $tableName);
$rows .= sprintf('<td rowspan="%s" colspan="0" class="bold">%s</td>', count($tableDiagnostic)+1, h($tableName));
$rows .= '</tr>';

View File

@ -6,9 +6,19 @@
<strong><?php echo __('Make sure you keep your API key secret as it gives access to the all of the data that you normally have access to in MISP.');?></strong>
<?php echo __('To view the old MISP automation page, click <a href="automation/1">here</a>.');?>
</p>
<p><?php echo __('Your current key is: <code>%s</code>.
You can %s this key.', $me['authkey'], $this->Html->link(__('reset'), array('controller' => 'users', 'action' => 'resetauthkey', 'me')));?>
</p>
<span>
<?php
echo __(
'Your current key is: <code>%s</code>. You can %s this key.',
$me['authkey'],
$this->Form->postLink(
__('reset'),
array('controller' => 'users', 'action' => 'resetauthkey', 'me'),
array('div' => false)
)
);
?>
</span>
<?php
$data = array(
'title' => __('Search'),

View File

@ -379,7 +379,7 @@
$count++;
if ($count == $display_threshold+1 && $total > $display_threshold):
?>
<div class="no-side-padding correlation-expand-button useCursorPointer linkButton blue"><?php echo __('Show (%s more)', $total - $count);?></div>
<div class="no-side-padding correlation-expand-button useCursorPointer linkButton blue"><?php echo __('Show (%s more)', $total - ($count-1));?></div>
<?php
endif;
?>

View File

@ -2,10 +2,16 @@
<?php echo $this->Form->create('Feed');?>
<fieldset>
<legend><?php echo __('Add MISP Feed');?></legend>
<p><?php echo __('Add a new MISP feed source.');?></p>
<?php
echo $this->Form->input('enabled', array());
echo $this->Form->input('caching_enabled', array('label' => __('Caching enabled')));
<?php
if (!empty(Configure::read('Security.disable_local_feed_access'))) {
echo sprintf(
'<p class="red bold">%s</p>',
__('Warning: local feeds are currently disabled by policy, to re-enable the feature, set the Security.allow_local_feed_access flag in the server settings. This setting can only be set via the CLI.')
);
}
echo '<p>' . __('Add a new MISP feed source.') . '</p>';
echo $this->Form->input('enabled', array());
echo $this->Form->input('caching_enabled', array('label' => __('Caching enabled')));
?>
<div class="input clear"></div>
<?php
@ -21,10 +27,14 @@
'placeholder' => __('Name of the content provider'),
'class' => 'form-control span6'
));
$options = array('network' => 'Network');
if (empty(Configure::read('Security.disable_local_feed_access'))) {
$options['local'] = 'Local';
}
echo $this->Form->input('input_source', array(
'label' => __('Input Source'),
'div' => 'input clear',
'options' => array('network' => 'Network', 'local' => 'Local'),
'options' => $options,
'class' => 'form-control span6'
));
?>

View File

@ -2,8 +2,14 @@
<?php echo $this->Form->create('Feed');?>
<fieldset>
<legend><?php echo __('Edit MISP Feed');?></legend>
<p><?php echo __('Edit a new MISP feed source.');?></p>
<?php
<?php
if (!empty(Configure::read('Security.disable_local_feed_access'))) {
echo sprintf(
'<p class="red bold">%s</p>',
__('Warning: local feeds are currently disabled by policy, to re-enable the feature, set the Security.allow_local_feed_access flag in the server settings. This setting can only be set via the CLI.')
);
}
echo '<p>' . __('Edit a new MISP feed source.') . '</p>';
echo $this->Form->input('enabled', array(
'type' => 'checkbox'
));
@ -26,9 +32,13 @@
'placeholder' => __('Name of the content provider'),
'class' => 'form-control span6'
));
$options = array('network' => 'Network');
if (empty(Configure::read('Security.disable_local_feed_access'))) {
$options['local'] = 'Local';
}
echo $this->Form->input('input_source', array(
'div' => 'input clear',
'options' => array('network' => 'Network', 'local' => 'Local'),
'options' => $options,
'class' => 'form-control span6'
));
?>

View File

@ -72,10 +72,11 @@
<div class="clear"><span role="button" tabindex="0" aria-label="<?php echo __('Fetch the user\'s GnuPG key');?>" onClick="lookupPGPKey('UserEmail');" class="btn btn-inverse" style="margin-bottom:10px;"><?php echo __('Fetch GnuPG key');?></span></div>
<?php
if (Configure::read('SMIME.enabled')) echo $this->Form->input('certif_public', array('label' => __('SMIME key'), 'div' => 'clear', 'class' => 'input-xxlarge', 'placeholder' => __('Paste the user\'s SMIME public key in PEM format here.')));
$default_publish_alert = Configure::check('MISP.default_publish_alert') ? Configure::read('MISP.default_publish_alert') : true;
echo $this->Form->input('autoalert', array(
'label' => __('Receive alerts when events are published'),
'type' => 'checkbox',
'checked' => isset($this->request->data['User']['autoalert']) ? $this->request->data['User']['autoalert'] : true
'checked' => isset($this->request->data['User']['autoalert']) ? $this->request->data['User']['autoalert'] : $default_publish_alert
));
echo $this->Form->input('contactalert', array(
'label' => __('Receive alerts from "contact reporter" requests'),

@ -1 +1 @@
Subproject commit 777c3188db6fd1f04fc81106a6c2eb293bb19d12
Subproject commit c7104e8819d6b789b24a45655aa28625a8c4c346

View File

@ -39,6 +39,8 @@ threat_actor_galaxies_list = ('threat-actor', 'microsoft-activity-group')
tool_galaxies_list = ('botnet', 'rat', 'exploit-kit', 'tds', 'tool', 'mitre-tool',
'mitre-enterprise-attack-tool', 'mitre-mobile-attack-tool')
_MISP_event_tags = ['Threat-Report', 'misp:tool="misp2stix2"']
_time_fields = {'indicator': ('valid_from', 'valid_until'),
'observed-data': ('first_observed', 'last_observed')}
class StixBuilder():
def __init__(self):
@ -73,6 +75,7 @@ class StixBuilder():
report_args = {'type': 'report', 'id': self.report_id, 'name': self.misp_event['info'],
'created_by_ref': self.identity_id, 'created': self.misp_event['date'],
'published': self.get_datetime_from_timestamp(self.misp_event['publish_timestamp']),
'modified': self.get_datetime_from_timestamp(self.misp_event['timestamp']),
'interoperability': True}
labels = [tag for tag in _MISP_event_tags]
if self.misp_event.get('Tag'):
@ -377,8 +380,7 @@ class StixBuilder():
self.galaxies.append(galaxy_uuid)
self.relationships['defined'][source_id].append("{}--{}".format(stix_type, galaxy_uuid))
@staticmethod
def generate_galaxy_args(galaxy, b_killchain, b_alias, sdo_type):
def generate_galaxy_args(self, galaxy, b_killchain, b_alias, sdo_type):
cluster = galaxy['GalaxyCluster'][0]
try:
cluster_uuid = cluster['collection_uuid']
@ -387,8 +389,9 @@ class StixBuilder():
sdo_id = "{}--{}".format(sdo_type, cluster_uuid)
description = "{} | {}".format(galaxy['description'], cluster['description'])
labels = ['misp:name=\"{}\"'.format(galaxy['name'])]
sdo_args = {'id': sdo_id, 'type': sdo_type, 'name': cluster['value'],
'description': description, 'interoperability': True}
sdo_args = {'id': sdo_id, 'type': sdo_type, 'created': self.misp_event['date'],
'modified': self.get_datetime_from_timestamp(self.misp_event['timestamp']),
'name': cluster['value'], 'description': description, 'interoperability': True}
if b_killchain:
killchain = [{'kill_chain_name': 'misp-category',
'phase_name': galaxy['type']}]
@ -452,8 +455,9 @@ class StixBuilder():
custom_object_id = "x-misp-object-{}--{}".format(attribute_type, attribute['uuid'])
custom_object_type = "x-misp-object-{}".format(attribute_type)
labels, markings = self.create_labels(attribute)
custom_object_args = {'id': custom_object_id, 'x_misp_category': attribute['category'], 'labels': labels,
'x_misp_timestamp': self.get_datetime_from_timestamp(attribute['timestamp']),
timestamp = self.get_datetime_from_timestamp(attribute['timestamp'])
custom_object_args = {'id': custom_object_id, 'x_misp_category': attribute['category'],
'created': timestamp, 'modified': timestamp, 'labels': labels,
'x_misp_value': attribute['value'], 'created_by_ref': self.identity_id}
if attribute.get('comment'):
custom_object_args['x_misp_comment'] = attribute['comment']
@ -461,14 +465,15 @@ class StixBuilder():
markings = self.handle_tags(markings)
custom_object_args['object_marking_refs'] = markings
@CustomObject(custom_object_type, [('id', properties.StringProperty(required=True)),
('x_misp_timestamp', properties.StringProperty(required=True)),
('labels', properties.ListProperty(labels, required=True)),
('x_misp_value', properties.StringProperty(required=True)),
('created_by_ref', properties.StringProperty(required=True)),
('object_marking_refs', properties.ListProperty(markings)),
('x_misp_comment', properties.StringProperty()),
('x_misp_category', properties.StringProperty())
])
('labels', properties.ListProperty(labels, required=True)),
('x_misp_value', properties.StringProperty(required=True)),
('created', properties.TimestampProperty(required=True, precision='millisecond')),
('modified', properties.TimestampProperty(required=True, precision='millisecond')),
('created_by_ref', properties.StringProperty(required=True)),
('object_marking_refs', properties.ListProperty(markings)),
('x_misp_comment', properties.StringProperty()),
('x_misp_category', properties.StringProperty())
])
class Custom(object):
def __init__(self, **kwargs):
return
@ -498,14 +503,11 @@ class StixBuilder():
labels, markings = self.create_labels(attribute)
attribute_value = attribute['value'] if attribute_type != "AS" else self.define_attribute_value(attribute['value'], attribute['comment'])
pattern = mispTypesMapping[attribute_type]['pattern'](attribute_type, attribute_value, attribute['data']) if attribute.get('data') else self.define_pattern(attribute_type, attribute_value)
indicator_args = {'id': indicator_id, 'type': 'indicator', 'labels': labels, 'kill_chain_phases': killchain,
'valid_from': self.misp_event['date'], 'created_by_ref': self.identity_id,
'pattern': pattern, 'interoperability': True}
if hasattr(attribute, 'Sighting'):
for sighting in attribute['Sighting']:
if sighting['Organisation']['name'] == self.misp_event['Orgc']['name'] and sighting['type'] == "2":
indicator_args['valid_until'] = self.get_datetime_from_timestamp(sighting['date_sighting'])
break
timestamp = self.get_datetime_from_timestamp(attribute['timestamp'])
indicator_args = {'id': indicator_id, 'type': 'indicator', 'labels': labels,
'kill_chain_phases': killchain, 'created_by_ref': self.identity_id,
'pattern': pattern, 'interoperability': True}
indicator_args.update(self.handle_time_fields(attribute, timestamp, 'indicator'))
if attribute.get('comment'):
indicator_args['description'] = attribute['comment']
if markings:
@ -534,8 +536,9 @@ class StixBuilder():
attribute_value = attribute['value'] if attribute_type != "AS" else self.define_attribute_value(attribute['value'], attribute['comment'])
observable = mispTypesMapping[attribute_type]['observable'](attribute_type, attribute_value, attribute['data']) if attribute.get('data') else self.define_observable(attribute_type, attribute_value)
observed_data_args = {'id': observed_data_id, 'type': 'observed-data', 'number_observed': 1,
'first_observed': timestamp, 'last_observed': timestamp, 'labels': labels,
'created_by_ref': self.identity_id, 'objects': observable, 'interoperability': True}
'objects': observable, 'created_by_ref': self.identity_id,
'labels': labels, 'interoperability': True}
observed_data_args.update(self.handle_time_fields(attribute, timestamp, 'observed-data'))
if markings:
observed_data_args['object_marking_refs'] = self.handle_tags(markings)
observed_data = ObservedData(**observed_data_args)
@ -593,15 +596,17 @@ class StixBuilder():
category = misp_object.get('meta-category')
labels = self.create_object_labels(name, category, to_ids)
values = self.fetch_custom_values(misp_object['Attribute'], custom_object_id)
custom_object_args = {'id': custom_object_id, 'x_misp_values': values, 'labels': labels,
'x_misp_category': category, 'created_by_ref': self.identity_id,
'x_misp_timestamp': self.get_datetime_from_timestamp(misp_object['timestamp'])}
timestamp = self.get_datetime_from_timestamp(misp_object['timestamp'])
custom_object_args = {'id': custom_object_id, 'x_misp_values': values,
'created': timestamp, 'modified': timestamp, 'labels': labels,
'x_misp_category': category, 'created_by_ref': self.identity_id}
if hasattr(misp_object, 'comment') and misp_object.get('comment'):
custom_object_args['x_misp_comment'] = misp_object['comment']
@CustomObject(custom_object_type, [('id', properties.StringProperty(required=True)),
('x_misp_timestamp', properties.StringProperty(required=True)),
('labels', properties.ListProperty(labels, required=True)),
('x_misp_values', properties.DictionaryProperty(required=True)),
('created', properties.TimestampProperty(required=True, precision='millisecond')),
('modified', properties.TimestampProperty(required=True, precision='millisecond')),
('created_by_ref', properties.StringProperty(required=True)),
('x_misp_comment', properties.StringProperty()),
('x_misp_category', properties.StringProperty())
@ -623,11 +628,13 @@ class StixBuilder():
category = misp_object.get('meta-category')
killchain = self.create_killchain(category)
labels = self.create_object_labels(name, category, True)
indicator_args = {'id': indicator_id, 'valid_from': self.misp_event['date'],
'type': 'indicator', 'labels': labels, 'pattern': pattern,
timestamp = self.get_datetime_from_timestamp(misp_object['timestamp'])
indicator_args = {'id': indicator_id, 'type': 'indicator',
'labels': labels, 'pattern': pattern,
'description': misp_object['description'], 'allow_custom': True,
'kill_chain_phases': killchain, 'interoperability': True,
'created_by_ref': self.identity_id}
indicator_args.update(self.handle_time_fields(misp_object, timestamp, 'indicator'))
indicator = Indicator(**indicator_args)
self.append_object(indicator)
@ -644,8 +651,8 @@ class StixBuilder():
timestamp = self.get_datetime_from_timestamp(misp_object['timestamp'])
observed_data_args = {'id': observed_data_id, 'type': 'observed-data', 'labels': labels,
'number_observed': 1, 'objects': observable_objects, 'allow_custom': True,
'first_observed': timestamp, 'last_observed': timestamp,
'created_by_ref': self.identity_id, 'interoperability': True}
observed_data_args.update(self.handle_time_fields(misp_object, timestamp, 'observed-data'))
try:
observed_data = ObservedData(**observed_data_args)
except exceptions.InvalidValueError:
@ -1417,6 +1424,13 @@ class StixBuilder():
def get_datetime_from_timestamp(timestamp):
return datetime.datetime.utcfromtimestamp(int(timestamp))
@staticmethod
def handle_time_fields(attribute, timestamp, stix_type):
to_return = {'created': timestamp, 'modified': timestamp}
for misp_field, stix_field in zip(('first_seen', 'last_seen'), _time_fields[stix_type]):
to_return[stix_field] = attribute[misp_field] if attribute[misp_field] else timestamp
return to_return
def main(args):
stix_builder = StixBuilder()
stix_builder.loadEvent(args)

@ -1 +1 @@
Subproject commit 00b6fafdff7c5242115f0f97be6247dc25fd1f09
Subproject commit 28687d90d575332776480cd5d683361e7485033c

View File

@ -766,7 +766,7 @@ class EventGraph {
group: group,
mass: 5,
};
if (node.type == 'attachment' && isPicture(node.value)) {
if (node.type == 'attachment' && isPicture(node.label)) {
// fetch picture via attributes/viewPicture
node_conf.group = 'attribute_image';
node_conf.size = $('#slider_display_picture_size').val();

@ -1 +1 @@
Subproject commit 77ca5ae2f9742652cd90a53f1b83308a8343f2cc
Subproject commit 65a943d8929c578041f789665b05810ea68986cb

File diff suppressed because it is too large Load Diff

21
debian/postinst vendored
View File

@ -29,7 +29,8 @@ if [ "$1" = "configure" ] ; then
cd /usr/share/misp/app
sudo -u www-data composer dump-autoload
sudo -u www-data composer install --ignore-platform-reqs
phpenmod redis
phpenmod gnupg
@ -55,9 +56,8 @@ if [ "$1" = "configure" ] ; then
mysql -h$HOST -uroot -p$ROOTPWD -e "CREATE USER IF NOT EXISTS '$MISPDBUSER'@'localhost' IDENTIFIED BY '$MISPDBUSERPWD';"
mysql -h$HOST -uroot -p$ROOTPWD -e "GRANT ALL PRIVILEGES ON misp.* TO '$MISPDBUSER'@'localhost';"
mysql -h$HOST -uroot -p$ROOTPWD -e "FLUSH PRIVILEGES;"
mysql -h$HOST -uroot -p$ROOTPWD -e "CREATE DATABASE $MISPDB;"
echo "Creating MISP Database..."
gunzip < /usr/share/doc/misp/MYSQL.sql.gz | mysql -h$HOST -u$MISPDBUSER -p$MISPDBUSERPWD $MISPDB
mysql -h$HOST -uroot -p$ROOTPWD -e "CREATE DATABASE $MISPDB;" && gunzip < /usr/share/doc/misp/MYSQL.sql.gz | mysql -h$HOST -u$MISPDBUSER -p$MISPDBUSERPWD $MISPDB || true
# /usr/share/misp/app/Config/database.php
echo "Updating salt..."
@ -69,11 +69,18 @@ if [ "$1" = "configure" ] ; then
sed -i -E "s/'password'\s=>\s'db password'/'password' => '$MISPDBUSERPWD'/" /usr/share/misp/app/Config/database.php
sed -i -E "s/'database'\s=>\s'misp'/'database' => '$MISPDB'/" /usr/share/misp/app/Config/database.php
composer require resque/php-resque || true
# composer require resque/php-resque || true
# No composer.json in current directory, do you want to use the one at /usr/share/misp/app? [Y,n]? Y
sudo -u www-data /usr/share/misp/app/Console/cake admin setSetting MISP.baseurl "$BASEURL"
echo "{\"major\":2, \"minor\":4, \"hotfix\":221}" > /usr/share/misp/VERSION.json
#
# Starting MISP Workers at every boot
#
chmod +x /usr/share/misp/app/Console/worker/start.sh
cat /usr/share/doc/misp/misp-workers.service > /etc/systemd/system/misp-workers.service
sed -i -E "s/\/var\/www\/MISP/\/usr\/share\/misp/" /etc/systemd/system/misp-workers.service
# systemctl daemon-reload
# systemctl enable --now misp-workers
fi