diff --git a/.travis.yml b/.travis.yml index 8a823eda2..e156bd36d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -102,7 +102,7 @@ install: - sudo -E su $USER -c 'app/Console/cake Admin setSetting "Session.cookieTimeout" 3600' - sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.host_org_id" 1' - sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.email" "info@admin.test"' - - sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.disable_emailing" true' + - sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.disable_emailing" false' - sudo -E su $USER -c 'app/Console/cake Admin setSetting "debug" true' - sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.CustomAuth_disable_logout" false' - sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.redis_host" "127.0.0.1"' @@ -160,10 +160,9 @@ script: - ./curl_tests.sh $AUTH - popd - pushd PyMISP + - git submodule init + - git submodule update - pipenv install -d - - pushd tests - - git clone https://github.com/viper-framework/viper-test-files.git - - popd - pipenv run python tests/testlive_comprehensive.py - pipenv run python tests/test.py - pipenv run python tests/test_mispevent.py diff --git a/INSTALL/INSTALL.sh b/INSTALL/INSTALL.sh index 8366d3119..266bc1a79 100644 --- a/INSTALL/INSTALL.sh +++ b/INSTALL/INSTALL.sh @@ -2464,6 +2464,7 @@ x86_64-debian-stretch x86_64-debian-buster x86_64-ubuntu-bionic x86_64-kali-2019.2 +x86_64-kali-2019.3 armv6l-raspbian-stretch armv7l-raspbian-stretch armv7l-debian-jessie diff --git a/INSTALL/INSTALL.sh.sfv b/INSTALL/INSTALL.sh.sfv index f86f05911..11c375fb1 100644 --- a/INSTALL/INSTALL.sh.sfv +++ b/INSTALL/INSTALL.sh.sfv @@ -1,5 +1,5 @@ -; Generated by RHash v1.3.8 on 2019-09-19 at 11:45.46 +; Generated by RHash v1.3.8 on 2019-10-12 at 23:45.03 ; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/ ; -; 98996 11:45.46 2019-09-19 INSTALL.sh -INSTALL.sh 590EBA6FCA2E8F2B5044843DF22FEED524ED3C7E 2B3E6DC0191D5D3AFD685E6ACF3E02D15261770E8E17A21F882EC2F07E908D55 13EB5B9EF3AEE3C96558DE068A0210F938491322F0AAD10DB958D9DCFA93B5313044013084E56647586AFCF8DE07C7D1 B169AA7096FAAF21E8CB8B7B7C9296C4CDB25E4B540637C15C040722EE52A2A8D2C4E8122CCEC25AFAD99F9CEC065DE14899E7C1DD571DE2B6127F08C6B79229 +; 99015 23:45.03 2019-10-12 INSTALL.sh +INSTALL.sh 0A4A963E90CD83550F59CBC270CEF3DB3E25DBDF D292D42E306A3E19FCD9A6C10B1A28F56584810D49420592A9A6644BB3EFB2E6 7453482ADF587B9760B23A0563FADE99568E497CF810BAE9CD7E44F0025D8D6BFE1B17DD2C790A6CCD72130A72CD59C6 E6BEACA555D8752D210757BE8A372AF7BA8675CA293810B8A5ADEE905FC44D41CDAD60225203D8E93B037D520703996E03E62B501EB766290C452716BB125C4F diff --git a/INSTALL/INSTALL.sh.sha1 b/INSTALL/INSTALL.sh.sha1 index 9ccef1a18..f1411624f 100644 --- a/INSTALL/INSTALL.sh.sha1 +++ b/INSTALL/INSTALL.sh.sha1 @@ -1 +1 @@ -590eba6fca2e8f2b5044843df22feed524ed3c7e INSTALL.sh +0a4a963e90cd83550f59cbc270cef3db3e25dbdf INSTALL.sh diff --git a/INSTALL/INSTALL.sh.sha256 b/INSTALL/INSTALL.sh.sha256 index fa10e2b37..def068cd8 100644 --- a/INSTALL/INSTALL.sh.sha256 +++ b/INSTALL/INSTALL.sh.sha256 @@ -1 +1 @@ -2b3e6dc0191d5d3afd685e6acf3e02d15261770e8e17a21f882ec2f07e908d55 INSTALL.sh +d292d42e306a3e19fcd9a6c10b1a28f56584810d49420592a9a6644bb3efb2e6 INSTALL.sh diff --git a/INSTALL/INSTALL.sh.sha384 b/INSTALL/INSTALL.sh.sha384 index 3172f0686..46f95f6c1 100644 --- a/INSTALL/INSTALL.sh.sha384 +++ b/INSTALL/INSTALL.sh.sha384 @@ -1 +1 @@ -13eb5b9ef3aee3c96558de068a0210f938491322f0aad10db958d9dcfa93b5313044013084e56647586afcf8de07c7d1 INSTALL.sh +7453482adf587b9760b23a0563fade99568e497cf810bae9cd7e44f0025d8d6bfe1b17dd2c790a6ccd72130a72cd59c6 INSTALL.sh diff --git a/INSTALL/INSTALL.sh.sha512 b/INSTALL/INSTALL.sh.sha512 index cf4f17fd2..68b123cbd 100644 --- a/INSTALL/INSTALL.sh.sha512 +++ b/INSTALL/INSTALL.sh.sha512 @@ -1 +1 @@ -b169aa7096faaf21e8cb8b7b7c9296c4cdb25e4b540637c15c040722ee52a2a8d2c4e8122ccec25afad99f9cec065de14899e7c1dd571de2b6127f08c6b79229 INSTALL.sh +e6beaca555d8752d210757be8a372af7ba8675ca293810b8a5adee905fc44d41cdad60225203d8e93b037d520703996e03e62b501eb766290c452716bb125c4f INSTALL.sh diff --git a/INSTALL/INSTALL.tpl.sh b/INSTALL/INSTALL.tpl.sh index 4a183f1cd..9b461b70c 100755 --- a/INSTALL/INSTALL.tpl.sh +++ b/INSTALL/INSTALL.tpl.sh @@ -678,6 +678,7 @@ x86_64-debian-stretch x86_64-debian-buster x86_64-ubuntu-bionic x86_64-kali-2019.2 +x86_64-kali-2019.3 armv6l-raspbian-stretch armv7l-raspbian-stretch armv7l-debian-jessie diff --git a/INSTALL/MYSQL.sql b/INSTALL/MYSQL.sql index 0c26a8045..86f42f950 100644 --- a/INSTALL/MYSQL.sql +++ b/INSTALL/MYSQL.sql @@ -1358,7 +1358,7 @@ INSERT INTO `admin_settings` (`id`, `setting`, `value`) VALUES 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), -(2, 'Botvrij.eu', 'The Botvrij.eu Data', 'http://www.botvrij.eu/data/feed-osint', 3, 1, 0); +(2, 'Botvrij.eu', 'The Botvrij.eu Data', 'https://www.botvrij.eu/data/feed-osint', 3, 1, 0); INSERT INTO `regexp` (`id`, `regexp`, `replacement`, `type`) VALUES (1, '/.:.ProgramData./i', '%ALLUSERSPROFILE%\\\\', 'ALL'), diff --git a/INSTALL/POSTGRESQL-data-initial.sql b/INSTALL/POSTGRESQL-data-initial.sql index ebb35f845..ca95d6d33 100644 --- a/INSTALL/POSTGRESQL-data-initial.sql +++ b/INSTALL/POSTGRESQL-data-initial.sql @@ -118,7 +118,7 @@ COPY public.favourite_tags (id, tag_id, user_id) FROM stdin; COPY public.feeds (id, name, provider, url, rules, enabled, distribution, sharing_group_id, tag_id, "default", source_format, fixed_event, delta_merge, event_id, publish, override_ids, settings, input_source, delete_local_file, lookup_visible, headers, caching_enabled) FROM stdin; 1 CIRCL OSINT Feed CIRCL https://www.circl.lu/doc/misp/feed-osint \N f 3 0 0 t misp f f 0 f f \N network f f \N f -2 The Botvrij.eu Data Botvrij.eu http://www.botvrij.eu/data/feed-osint \N f 3 0 0 t misp f f 0 f f \N network f f \N f +2 The Botvrij.eu Data Botvrij.eu https://www.botvrij.eu/data/feed-osint \N f 3 0 0 t misp f f 0 f f \N network f f \N f \. diff --git a/INSTALL/misplogrotate.te b/INSTALL/misplogrotate.te index 9d8d28ebc..921989772 100644 --- a/INSTALL/misplogrotate.te +++ b/INSTALL/misplogrotate.te @@ -1,8 +1,16 @@ -module misplogrotate 1.0; +module misplogrotate 1.2; require { + type httpd_t; type logrotate_t; + type httpd_log_t; + type httpd_sys_script_t; type httpd_sys_content_t; - class dir { ioctl read getattr lock search open }; + type httpd_sys_rw_content_t; + class dir { ioctl read getattr lock search open remove_name }; + class file { unlink write }; } #============= logrotate_t ============== allow logrotate_t httpd_sys_content_t:dir { ioctl read getattr lock search open }; +allow logrotate_t httpd_sys_rw_content_t:dir { ioctl read getattr lock search open }; +allow httpd_t httpd_log_t:dir remove_name; +allow { httpd_t httpd_sys_script_t } httpd_log_t:file { unlink write }; diff --git a/PyMISP b/PyMISP index de6a64ba4..204fd6ba8 160000 --- a/PyMISP +++ b/PyMISP @@ -1 +1 @@ -Subproject commit de6a64ba45b56cef1a233df306da411c49801c03 +Subproject commit 204fd6ba8cc916844156c1819c8375f6bbbca995 diff --git a/VERSION.json b/VERSION.json index 4f4c7e5f5..f0d1fb40b 100644 --- a/VERSION.json +++ b/VERSION.json @@ -1 +1 @@ -{"major":2, "minor":4, "hotfix":116} +{"major":2, "minor":4, "hotfix":117} diff --git a/app/Config/config.default.php b/app/Config/config.default.php index 9f190e3f5..dc55fb86e 100644 --- a/app/Config/config.default.php +++ b/app/Config/config.default.php @@ -17,7 +17,7 @@ $config = array( 'org' => 'ORGNAME', 'showorg' => true, 'threatlevel_in_email_subject' => true, - 'email_subject_TLP_string' => 'TLP Amber', + 'email_subject_TLP_string' => 'tlp:amber', 'email_subject_tag' => 'tlp', 'email_subject_include_tag_name' => true, 'background_jobs' => true, @@ -141,7 +141,7 @@ $config = array( /* 'ApacheSecureAuth' => // Configuration for kerberos authentication array( - 'apacheEnv' => 'REMOTE_USER', // If proxy variable = HTTP_REMOTE_USER + 'apacheEnv' => 'REMOTE_USER', // If proxy variable = HTTP_REMOTE_USER, If BasicAuth ldap = PHP_AUTH_USER 'ldapServer' => 'ldap://example.com', // FQDN or IP 'ldapProtocol' => 3, 'ldapNetworkTimeout' => -1, // use -1 for unlimited network timeout diff --git a/app/Console/Command/ServerShell.php b/app/Console/Command/ServerShell.php index 215404032..52da69563 100644 --- a/app/Console/Command/ServerShell.php +++ b/app/Console/Command/ServerShell.php @@ -6,6 +6,32 @@ class ServerShell extends AppShell { public $uses = array('Server', 'Task', 'Job', 'User', 'Feed'); + public function list() { + $res = ['servers'=>[]]; + + $servers = $this->Server->find('all', [ + 'fields' => ['Server.id', 'Server.name', 'Server.url'], + 'recursive' => 0 + ]); + foreach ($servers as $server) + $res['servers'][] = $server['Server']; + + echo json_encode($res) . PHP_EOL; + } + + public function test() { + if (empty($this->args[0])) { + die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['Test'] . PHP_EOL); + } + + $serverId = intval($this->args[0]); + $res = @$this->Server->runConnectionTest($serverId); + if (!empty($res['message'])) + $res['message'] = json_decode($res['message']); + + echo json_encode($res) . PHP_EOL; + } + public function pull() { if (empty($this->args[0]) || empty($this->args[1])) { die('Usage: ' . $this->Server->command_line_functions['console_automation_tasks']['data']['pull'] . PHP_EOL); diff --git a/app/Controller/AppController.php b/app/Controller/AppController.php index 77e9b0473..736a568f7 100755 --- a/app/Controller/AppController.php +++ b/app/Controller/AppController.php @@ -46,8 +46,8 @@ class AppController extends Controller public $helpers = array('Utility', 'OrgImg', 'FontAwesome', 'UserName'); - private $__queryVersion = '89'; - public $pyMispVersion = '2.4.114'; + private $__queryVersion = '90'; + public $pyMispVersion = '2.4.117'; public $phpmin = '7.0'; public $phprec = '7.2'; public $isApiAuthed = false; @@ -471,7 +471,9 @@ class AppController extends Controller } $this->set('notifications', $notifications); $this->ACL->checkAccess($this->Auth->user(), Inflector::variable($this->request->params['controller']), $this->action); - $this->__rateLimitCheck(); + if ($this->_isRest()) { + $this->__rateLimitCheck(); + } } private function __rateLimitCheck() diff --git a/app/Controller/AttributesController.php b/app/Controller/AttributesController.php index bf126a45d..f076ddfb5 100644 --- a/app/Controller/AttributesController.php +++ b/app/Controller/AttributesController.php @@ -80,18 +80,10 @@ class AttributesController extends AppController return $this->RestResponse->viewData($attributes, $this->response->type()); } $org_ids = array(); - $tag_ids = array(); $orgs = $this->Attribute->Event->Orgc->find('list', array( 'conditions' => array('Orgc.id' => $org_ids), 'fields' => array('Orgc.id', 'Orgc.name') )); - if (!empty($tag_ids)) { - $tags = $this->Attribute->AttributeTag->Tag->find('all', array( - 'conditions' => array('Tag.id' => $tag_ids), - 'recursive' => -1, - 'fields' => array('Tag.id', 'Tag.name', 'Tag.colour') - )); - } if (!$this->_isRest()) { $temp = $this->__searchUI($attributes); $this->loadModel('Galaxy'); @@ -1645,25 +1637,6 @@ class AttributesController extends AppController } } - // Deletes this specific attribute from all remote servers - private function __deleteAttributeFromServers($uuid) - { - // get a list of the servers with push active - $this->loadModel('Server'); - $servers = $this->Server->find('all', array('conditions' => array('push' => 1))); - - // iterate over the servers and upload the attribute - if (empty($servers)) { - return; - } - App::uses('SyncTool', 'Tools'); - foreach ($servers as $server) { - $syncTool = new SyncTool(); - $HttpSocket = $syncTool->setupHttpSocket($server); - $this->Attribute->deleteAttributeFromServer($uuid, $server, $HttpSocket); - } - } - public function search($continue = false) { $this->set('attrDescriptions', $this->Attribute->fieldDescriptions); @@ -2986,6 +2959,7 @@ class AttributesController extends AppController public function addTag($id = false, $tag_id = false) { + $this->Taxonomy = $log = ClassRegistry::init('Taxonomy'); $rearrangeRules = array( 'request' => false, 'Attribute' => false, @@ -3126,6 +3100,20 @@ class AttributesController extends AppController $fails++; continue; } + $tagsOnAttribute = $this->Attribute->AttributeTag->find('all', array( + 'conditions' => array( + 'AttributeTag.attribute_id' => $id, + 'AttributeTag.local' => $local + ), + 'contain' => 'Tag', + 'fields' => array('Tag.name'), + 'recursive' => -1 + )); + $exclusiveTestPassed = $this->Taxonomy->checkIfNewTagIsAllowedByTaxonomy($tag['Tag']['name'], Hash::extract($tagsOnAttribute, '{n}.Tag.name')); + if (!$exclusiveTestPassed) { + $fails++; + continue; + } $this->Attribute->AttributeTag->create(); if ($this->Attribute->AttributeTag->save(array('attribute_id' => $id, 'tag_id' => $tag_id, 'event_id' => $eventId, 'local' => $local))) { if (!$local) { diff --git a/app/Controller/EventsController.php b/app/Controller/EventsController.php index ea9baf258..e68a6f748 100644 --- a/app/Controller/EventsController.php +++ b/app/Controller/EventsController.php @@ -1150,6 +1150,7 @@ class EventsController extends AppController // remove galaxies tags $this->loadModel('GalaxyCluster'); + $this->loadModel('Taxonomy'); $cluster_names = $this->GalaxyCluster->find('list', array('fields' => array('GalaxyCluster.tag_name'), 'group' => array('GalaxyCluster.tag_name', 'GalaxyCluster.id'))); foreach ($event['Object'] as $k => $object) { if (isset($object['Attribute'])) { @@ -1159,6 +1160,14 @@ class EventsController extends AppController unset($event['Object'][$k]['Attribute'][$k2]['AttributeTag'][$k3]); } } + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($attribute['AttributeTag']); + foreach ($tagConflicts['global'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + foreach ($tagConflicts['local'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + $event['Object'][$k]['Attribute'][$k2]['tagConflicts'] = $tagConflicts; } } } @@ -1168,6 +1177,14 @@ class EventsController extends AppController unset($event['Attribute'][$k]['AttributeTag'][$k2]); } } + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($attribute['AttributeTag']); + foreach ($tagConflicts['global'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + foreach ($tagConflicts['local'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + $event['Attribute'][$k]['tagConflicts'] = $tagConflicts; } if (empty($this->passedArgs['sort'])) { $filters['sort'] = 'timestamp'; @@ -1258,12 +1275,14 @@ class EventsController extends AppController private function __viewUI($event, $continue, $fromEvent) { + $this->loadModel('Taxonomy'); $filterData = array( 'request' => $this->request, 'paramArray' => $this->acceptedFilteringNamedParams, 'named_params' => $this->params['named'] ); $exception = false; + $warningTagConflicts = array(); $filters = $this->_harvestParameters($filterData, $exception); $this->loadModel('GalaxyCluster'); @@ -1364,6 +1383,16 @@ class EventsController extends AppController unset($event['EventTag'][$k]); } } + + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($event['EventTag']); + foreach ($tagConflicts['global'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + foreach ($tagConflicts['local'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + $this->set('tagConflicts', $tagConflicts); + $startDate = null; $modificationMap = array(); foreach ($event['Attribute'] as $k => $attribute) { @@ -1380,6 +1409,14 @@ class EventsController extends AppController unset($event['Attribute'][$k]['AttributeTag'][$k2]); } } + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($attribute['AttributeTag']); + foreach ($tagConflicts['global'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + foreach ($tagConflicts['local'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + $event['Attribute'][$k]['tagConflicts'] = $tagConflicts; } $attributeTagsName = $this->Event->Attribute->AttributeTag->extractAttributeTagsNameFromEvent($event, 'both'); $this->set('attributeTags', array_values($attributeTagsName['tags'])); @@ -1405,9 +1442,18 @@ class EventsController extends AppController unset($event['Object'][$k]['Attribute'][$k2]['AttributeTag'][$k3]); } } + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($attribute['AttributeTag']); + foreach ($tagConflicts['global'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + foreach ($tagConflicts['local'] as $tagConflict) { + $warningTagConflicts[$tagConflict['taxonomy']['Taxonomy']['namespace']] = $tagConflict['taxonomy']; + } + $event['Object'][$k]['Attribute'][$k2]['tagConflicts'] = $tagConflicts; } } } + $this->set('warningTagConflicts', $warningTagConflicts); $filters['sort'] = 'timestamp'; $filters['direction'] = 'desc'; if (isset($filters['distribution'])) { @@ -3715,6 +3761,7 @@ class EventsController extends AppController public function addTag($id = false, $tag_id = false) { + $this->loadModel('Taxonomy'); $rearrangeRules = array( 'request' => false, 'Event' => false, @@ -3829,6 +3876,20 @@ class EventsController extends AppController $error = __('Tag is already attached to this event.'); continue; } + $tagsOnEvent = $this->Event->EventTag->find('all', array( + 'conditions' => array( + 'EventTag.event_id' => $id, + 'EventTag.local' => $local + ), + 'contain' => 'Tag', + 'fields' => array('Tag.name'), + 'recursive' => -1 + )); + $exclusiveTestPassed = $this->Taxonomy->checkIfNewTagIsAllowedByTaxonomy($tag['Tag']['name'], Hash::extract($tagsOnEvent, '{n}.Tag.name')); + if (!$exclusiveTestPassed) { + $fail = __('Tag is not allowed due to taxonomy exclusivity settings'); + continue; + } $this->Event->EventTag->create(); if ($this->Event->EventTag->save(array('event_id' => $id, 'tag_id' => $tag_id, 'local' => $local))) { if (!$local) { @@ -4456,12 +4517,12 @@ class EventsController extends AppController 'checkbox_set' => '/events/restSearch/stix/eventid:' . $id . '/withAttachments:1' ), 'stix_json' => array( - 'url' => '/events/restSearch/stix/eventid:' . $id . '.json', + 'url' => '/events/restSearch/stix-json/eventid:' . $id, 'text' => 'STIX JSON (metadata + all attributes)', 'requiresPublished' => false, 'checkbox' => true, 'checkbox_text' => 'Encode Attachments', - 'checkbox_set' => '/events/restSearch/stix/withAttachments:1/eventid:' . $id . '.json' + 'checkbox_set' => '/events/restSearch/stix-json/withAttachments:1/eventid:' . $id ), 'stix2_json' => array( 'url' => '/events/restSearch/stix2/eventid:' . $id, diff --git a/app/Controller/TagCollectionsController.php b/app/Controller/TagCollectionsController.php index ea15fc20b..ee3060b39 100644 --- a/app/Controller/TagCollectionsController.php +++ b/app/Controller/TagCollectionsController.php @@ -237,6 +237,9 @@ class TagCollectionsController extends AppController $RearrangeTool = new RequestRearrangeTool(); $this->request->data = $RearrangeTool->rearrangeArray($this->request->data, $rearrangeRules); if ($id === false) { + if (!isset($this->request->data['tag_collection'])) { + throw new NotFoundException(__('Invalid tag collection')); + } $id = $this->request->data['tag_collection']; } if (!$this->request->is('post')) { @@ -247,6 +250,9 @@ class TagCollectionsController extends AppController $this->render('/Events/add_tag'); } else { if ($tag_id === false) { + if (!isset($this->request->data['tag'])) { + throw new NotFoundException(__('Invalid tag')); + } $tag_id = $this->request->data['tag']; } $conditions = array(); diff --git a/app/Controller/TagsController.php b/app/Controller/TagsController.php index e75f36d0c..c5c1e9778 100644 --- a/app/Controller/TagsController.php +++ b/app/Controller/TagsController.php @@ -459,6 +459,7 @@ class TagsController extends AppController public function showEventTag($id) { $this->loadModel('EventTag'); + $this->loadModel('Taxonomy'); if (!$this->EventTag->Event->checkIfAuthorised($this->Auth->user(), $id)) { throw new MethodNotAllowedException('Invalid event.'); } @@ -487,6 +488,8 @@ class TagsController extends AppController 'conditions' => array('Event.id' => $id) )); $this->set('required_taxonomies', $this->EventTag->Event->getRequiredTaxonomies()); + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($tags); + $this->set('tagConflicts', $tagConflicts); $this->set('event', $event); $this->layout = 'ajax'; $this->render('/Events/ajax/ajaxTags'); @@ -496,6 +499,7 @@ class TagsController extends AppController { $this->helpers[] = 'TextColour'; $this->loadModel('AttributeTag'); + $this->loadModel('Taxonomy'); $this->Tag->AttributeTag->Attribute->id = $id; if (!$this->Tag->AttributeTag->Attribute->exists()) { @@ -528,6 +532,8 @@ class TagsController extends AppController $this->set('event', $event); $this->set('attributeTags', $attributeTags); $this->set('attributeId', $id); + $tagConflicts = $this->Taxonomy->checkIfTagInconsistencies($attributeTags); + $this->set('tagConflicts', $tagConflicts); $this->layout = 'ajax'; $this->render('/Attributes/ajax/ajaxAttributeTags'); } diff --git a/app/Controller/UserSettingsController.php b/app/Controller/UserSettingsController.php index 47b728c72..ed4faacf4 100644 --- a/app/Controller/UserSettingsController.php +++ b/app/Controller/UserSettingsController.php @@ -103,7 +103,15 @@ class UserSettingsController extends AppController return $this->RestResponse->viewData($userSettings, $this->response->type()); } else { $this->paginate['conditions'] = $conditions; - $this->set('data', $this->paginate()); + $data = $this->paginate(); + foreach ($data as $k => $v) { + if (!empty($this->UserSetting->validSettings[$v['UserSetting']['setting']])) { + $data[$k]['UserSetting']['restricted'] = empty($this->UserSetting->validSettings[$v['UserSetting']['setting']]['restricted']) ? '' : $this->UserSetting->validSettings[$v['UserSetting']['setting']]['restricted']; + } else { + $data[$k]['UserSetting']['restricted'] = array(); + } + } + $this->set('data', $data); $this->set('context', empty($context) ? 'null' : $context); } } @@ -138,6 +146,15 @@ class UserSettingsController extends AppController public function setSetting($user_id = false, $setting = false) { + if (!empty($setting)) { + if (!$this->UserSetting->checkSettingValidity($setting)) { + throw new MethodNotAllowedException(__('Invalid setting.')); + } + $settingPermCheck = $this->UserSetting->checkSettingAccess($this->Auth->user(), $setting); + if ($settingPermCheck !== true) { + throw new MethodNotAllowedException(__('This setting is restricted and requires the following permission(s): %s', $settingPermCheck)); + } + } // handle POST requests if ($this->request->is('post')) { // massage the request to allow for unencapsulated POST requests via the API @@ -168,16 +185,22 @@ class UserSettingsController extends AppController $userSetting['user_id'] = $this->request->data['UserSetting']['user_id']; } } - if (empty($this->request->data['UserSetting']['setting'])) { + if (empty($this->request->data['UserSetting']['setting']) || !isset($this->request->data['UserSetting']['setting'])) { throw new MethodNotAllowedException(__('This endpoint expects both a setting and a value to be set.')); - } else { - if (!$this->UserSetting->checkSettingValidity($this->request->data['UserSetting']['setting'])) { - throw new MethodNotAllowedException(__('Invalid setting.')); - } - $userSetting['setting'] = $this->request->data['UserSetting']['setting']; } - $userSetting['value'] = empty($this->request->data['UserSetting']['value']) ? '' : - json_encode(json_decode($this->request->data['UserSetting']['value'], true)); + if (!$this->UserSetting->checkSettingValidity($this->request->data['UserSetting']['setting'])) { + throw new MethodNotAllowedException(__('Invalid setting.')); + } + $settingPermCheck = $this->UserSetting->checkSettingAccess($this->Auth->user(), $this->request->data['UserSetting']['setting']); + if ($settingPermCheck !== true) { + throw new MethodNotAllowedException(__('This setting is restricted and requires the following permission(s): %s', $settingPermCheck)); + } + $userSetting['setting'] = $this->request->data['UserSetting']['setting']; + if ($this->request->data['UserSetting']['value'] !== '') { + $userSetting['value'] = json_encode(json_decode($this->request->data['UserSetting']['value'], true)); + } else { + $userSetting['value'] = ''; + } $existingSetting = $this->UserSetting->find('first', array( 'recursive' => -1, 'conditions' => array( @@ -243,6 +266,7 @@ class UserSettingsController extends AppController if (!empty($user_id) && $this->request->is('get')) { $this->request->data['UserSetting']['user_id'] = $user_id; } + $this->set('setting', $setting); $this->set('users', $users); $this->set('validSettings', $validSettings); } @@ -301,6 +325,10 @@ class UserSettingsController extends AppController if (!$checkAccess) { throw new NotFoundException(__('Invalid user setting.')); } + $settingPermCheck = $this->UserSetting->checkSettingAccess($this->Auth->user(), $userSetting['UserSetting']['setting']); + if ($settingPermCheck !== true) { + throw new MethodNotAllowedException(__('This setting is restricted and requires the following permission(s): %s', $settingPermCheck)); + } if ($this->request->is('post') || $this->request->is('delete')) { // Delete the setting that we were after. $result = $this->UserSetting->delete($userSetting['UserSetting']['id']); diff --git a/app/Controller/UsersController.php b/app/Controller/UsersController.php index 5a63db404..d97a89ba1 100644 --- a/app/Controller/UsersController.php +++ b/app/Controller/UsersController.php @@ -48,12 +48,19 @@ class UsersController extends AppController )); $id = $userid['User']['id']; } - $this->User->id = $id; - $this->User->recursive = 0; - if (!$this->User->exists()) { + $user = $this->User->read(null, $id); + $user = $this->User->find('first', array( + 'recursive' => -1, + 'conditions' => array('User.id' => $id), + 'contain' => array( + 'UserSetting', + 'Role', + 'Organisation' + ) + )); + if (empty($user)) { throw new NotFoundException(__('Invalid user')); } - $user = $this->User->read(null, $id); if (!empty($user['User']['gpgkey'])) { $pgpDetails = $this->User->verifySingleGPG($user); $user['User']['pgp_status'] = isset($pgpDetails[2]) ? $pgpDetails[2] : 'OK'; @@ -62,9 +69,15 @@ class UsersController extends AppController if ($this->_isRest()) { unset($user['User']['server_id']); $user['User']['password'] = '*****'; + $temp = array(); + foreach ($user['UserSetting'] as $k => $v) { + $temp[$v['setting']] = $v['value']; + } + $user['UserSetting'] = $temp; return $this->RestResponse->viewData(array( 'User' => $user['User'], - 'Role' => $user['Role'] + 'Role' => $user['Role'], + 'UserSetting' => $user['UserSetting'] ), $this->response->type()); } else { $this->set('user', $user); @@ -465,11 +478,17 @@ class UsersController extends AppController public function admin_view($id = null) { - $this->User->id = $id; - if (!$this->User->exists()) { + $user = $this->User->find('first', array( + 'recursive' => -1, + 'conditions' => array('User.id' => $id), + 'contain' => array( + 'UserSetting', + 'Role' + ) + )); + if (empty($user)) { throw new NotFoundException(__('Invalid user')); } - $user = $this->User->read(null, $id); if (!empty($user['User']['gpgkey'])) { $pgpDetails = $this->User->verifySingleGPG($user); $user['User']['pgp_status'] = isset($pgpDetails[2]) ? $pgpDetails[2] : 'OK'; @@ -485,6 +504,16 @@ class UsersController extends AppController } if ($this->_isRest()) { $user['User']['password'] = '*****'; + $temp = array(); + foreach ($user['UserSetting'] as $k => $v) { + $temp[$v['setting']] = $v['value']; + } + $user['UserSetting'] = $temp; + return $this->RestResponse->viewData(array( + 'User' => $user['User'], + 'Role' => $user['Role'], + 'UserSetting' => $user['UserSetting'] + ), $this->response->type()); return $this->RestResponse->viewData(array('User' => $user['User']), $this->response->type()); } else { $temp = $this->User->data['User']['invited_by']; diff --git a/app/Lib/Export/Stix1Export.php b/app/Lib/Export/Stix1Export.php index 7968b4910..c3035ba5d 100644 --- a/app/Lib/Export/Stix1Export.php +++ b/app/Lib/Export/Stix1Export.php @@ -15,13 +15,13 @@ class Stix1Export extends StixExport $this->__org = escapeshellarg(Configure::read('MISP.org')); $framing_file = $this->__scripts_dir . 'misp_framing.py '; $my_server = ClassRegistry::init('Server'); - return $my_server->getPythonVersion() . ' ' . $framing_file . $this->__return_type . ' ' . $this->__baseurl . ' ' . $this->__org . ' xml' . $this->__end_of_cmd; + return $my_server->getPythonVersion() . ' ' . $framing_file . $this->__return_type . ' ' . $this->__baseurl . ' ' . $this->__org . ' ' . $this->__return_format . ' ' . $this->__end_of_cmd; } protected function __parse_misp_events($filename) { $scriptFile = $this->__scripts_dir . $this->__script_name; $my_server = ClassRegistry::init('Server'); - return shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . ' xml ' . $this->__baseurl . ' ' . $this->__org . $this->__end_of_cmd); + return shell_exec($my_server->getPythonVersion() . ' ' . $scriptFile . ' ' . $filename . ' ' . $this->__return_format . ' ' . $this->__baseurl . ' ' . $this->__org . $this->__end_of_cmd); } } diff --git a/app/Lib/Export/StixExport.php b/app/Lib/Export/StixExport.php index 01e7c5b26..56ef36315 100644 --- a/app/Lib/Export/StixExport.php +++ b/app/Lib/Export/StixExport.php @@ -2,6 +2,11 @@ class StixExport { + public $additional_params = array( + 'includeEventTags' => 1, + 'includeGalaxy' => 1 + ); + protected $__return_format = 'json'; protected $__scripts_dir = APP . 'files/scripts/'; protected $__end_of_cmd = ' 2>' . APP . 'tmp/logs/exec-errors.log'; protected $__return_type = null; @@ -54,6 +59,11 @@ class StixExport public function header($options = array()) { $this->__return_type = $options['returnFormat']; + if ($this->__return_type == 'stix-json') { + $this->__return_type = 'stix'; + } else if ($this->__return_type == 'stix') { + $this->__return_format = 'xml'; + } $framing_cmd = $this->initiate_framing_params(); $randomFileName = $this->__generateRandomFileName(); $this->__tmp_dir = $this->__scripts_dir . 'tmp/'; diff --git a/app/Lib/Tools/EventGraphTool.php b/app/Lib/Tools/EventGraphTool.php index cb63213d8..adda8c2e0 100644 --- a/app/Lib/Tools/EventGraphTool.php +++ b/app/Lib/Tools/EventGraphTool.php @@ -265,7 +265,7 @@ foreach ($object as $obj) { $toPush = array( - 'id' => $obj['id'], + 'id' => sprintf('o-%s', $obj['id']), 'uuid' => $obj['uuid'], 'type' => $obj['name'], 'label' => '', @@ -290,8 +290,8 @@ $toPush = array( 'id' => $rel['id'], 'uuid' => $rel['uuid'], - 'from' => $obj['id'], - 'to' => $rel['referenced_id'], + 'from' => sprintf('o-%s', $obj['id']), + 'to' => $rel['referenced_type'] == 1 ? sprintf('o-%s', $rel['referenced_id']) : $rel['referenced_id'], 'type' => $rel['relationship_type'], 'comment' => $rel['comment'], 'event_id' => $rel['event_id'], @@ -356,7 +356,7 @@ foreach ($object as $obj) { $toPush = array( - 'id' => $obj['id'], + 'id' => sprintf('o-%s', $obj['id']), 'uuid' => $obj['uuid'], 'type' => $obj['name'], 'Attribute' => $obj['Attribute'], @@ -382,7 +382,7 @@ if (!in_array($tag['name'], $added_value)) { $toPush = array( 'id' => "tag_edge_id_" . $i, - 'from' => $obj['id'], + 'from' => sprintf('o-%s', $obj['id']), 'to' => $tag['name'], ); $tagSet[$tag['name']] = $tag; @@ -466,7 +466,7 @@ foreach ($object as $obj) { $toPush = array( - 'id' => $obj['id'], + 'id' => sprintf('o-%s', $obj['id']), 'uuid' => $obj['uuid'], 'type' => $obj['name'], 'Attribute' => $obj['Attribute'], @@ -491,7 +491,7 @@ if (!in_array($keyVal, $added_value)) { $toPush = array( 'id' => "keyType_edge_id_" . $i, - 'from' => $obj['id'], + 'from' => sprintf('o-%s', $obj['id']), 'to' => "keyType_" . $keyVal, ); array_push($added_value, $keyVal); diff --git a/app/Model/AppModel.php b/app/Model/AppModel.php index 75171aaef..dd7ead95d 100644 --- a/app/Model/AppModel.php +++ b/app/Model/AppModel.php @@ -142,7 +142,7 @@ class AppModel extends Model break; case '2.4.27': $newFeeds = array( - array('provider' => 'Botvrij.eu', 'name' => 'The Botvrij.eu Data','url' => 'http://www.botvrij.eu/data/feed-osint', 'enabled' => 0) + array('provider' => 'Botvrij.eu', 'name' => 'The Botvrij.eu Data','url' => 'https://www.botvrij.eu/data/feed-osint', 'enabled' => 0) ); $this->__addNewFeeds($newFeeds); break; diff --git a/app/Model/Behavior/RegexpBehavior.php b/app/Model/Behavior/RegexpBehavior.php index 60d9ffa76..11dbd1fbe 100644 --- a/app/Model/Behavior/RegexpBehavior.php +++ b/app/Model/Behavior/RegexpBehavior.php @@ -4,37 +4,40 @@ App::uses('Regexp', 'Model'); /** * Behavior to regexp all string fields in a model - * */ class RegexpBehavior extends ModelBehavior { - private $__allRegexp = array(); + private $__allRegexp = null; public $excluded_types = array('sigma', 'float'); - public function setup(Model $model, $config = null) - { - $regexp = new Regexp(); - $this->__allRegexp = $regexp->find('all', array('order' => 'id ASC')); - } - /** * replace the current value according to the regexp rules, or block blacklisted regular expressions * * @param Model $Model - * @param unknown_type $array + * @param string $type + * @param string $value + * @return string */ public function runRegexp(Model $Model, $type, $value) { if (in_array($type, $this->excluded_types)) { return $value; } + + if ($this->__allRegexp === null) { + $regexp = new Regexp(); + $this->__allRegexp = $regexp->find('all', array('order' => 'id ASC')); + } + foreach ($this->__allRegexp as $regexp) { - if (!empty($regexp['Regexp']['replacement']) && !empty($regexp['Regexp']['regexp']) && ($regexp['Regexp']['type'] === 'ALL' || $regexp['Regexp']['type'] === $type)) { - $value = preg_replace($regexp['Regexp']['regexp'], $regexp['Regexp']['replacement'], $value); - } - if (empty($regexp['Regexp']['replacement']) && preg_match($regexp['Regexp']['regexp'], $value) && ($regexp['Regexp']['type'] === 'ALL' || $regexp['Regexp']['type'] === $type)) { - return false; + if ($regexp['Regexp']['type'] === 'ALL' || $regexp['Regexp']['type'] === $type) { + if (!empty($regexp['Regexp']['replacement']) && !empty($regexp['Regexp']['regexp'])) { + $value = preg_replace($regexp['Regexp']['regexp'], $regexp['Regexp']['replacement'], $value); + } + if (empty($regexp['Regexp']['replacement']) && preg_match($regexp['Regexp']['regexp'], $value)) { + return false; + } } } return $value; diff --git a/app/Model/DecayingModelsFormulas/Base.php b/app/Model/DecayingModelsFormulas/Base.php index 3ba47c53a..73f491037 100644 --- a/app/Model/DecayingModelsFormulas/Base.php +++ b/app/Model/DecayingModelsFormulas/Base.php @@ -124,5 +124,3 @@ abstract class DecayingModelBase // Return a True if the attribute should be marked as decayed abstract public function isDecayed($model, $attribute, $score); } - -?> diff --git a/app/Model/DecayingModelsFormulas/Polynomial.php b/app/Model/DecayingModelsFormulas/Polynomial.php index dcb75d8da..a981122e8 100644 --- a/app/Model/DecayingModelsFormulas/Polynomial.php +++ b/app/Model/DecayingModelsFormulas/Polynomial.php @@ -24,4 +24,3 @@ class Polynomial extends DecayingModelBase return $threshold > $score; } } -?> diff --git a/app/Model/DecayingModelsFormulas/PolynomialExtended.php b/app/Model/DecayingModelsFormulas/PolynomialExtended.php index 4d8e54db8..4fa8ecfbb 100644 --- a/app/Model/DecayingModelsFormulas/PolynomialExtended.php +++ b/app/Model/DecayingModelsFormulas/PolynomialExtended.php @@ -51,4 +51,3 @@ class PolynomialExtended extends Polynomial return parent::isDecayed($model, $attribute, $score); } } -?> diff --git a/app/Model/Event.php b/app/Model/Event.php index 59c48d7d1..24d03eff8 100755 --- a/app/Model/Event.php +++ b/app/Model/Event.php @@ -121,7 +121,15 @@ class Event extends AppModel 'scope' => 'Event', 'requiresPublished' => 1, 'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1), - 'description' => 'Click this to download an a STIX document containing the STIX version of all events and attributes that you have access to.' + 'description' => 'Click this to download a STIX document containing the STIX version of all events and attributes that you have access to.' + ), + 'stix-json' => array( + 'extension' => '.json', + 'type' => 'STIX', + 'scope' => 'Event', + 'requiresPublished' => 1, + 'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1), + 'description' => 'Click this to download a STIX document containing the STIX version of all events and attributes that you have access to.' ), 'stix2' => array( 'extension' => '.json', @@ -129,7 +137,7 @@ class Event extends AppModel 'scope' => 'Event', 'requiresPublished' => 1, 'params' => array('returnFormat' => 'stix2', 'includeAttachments' => 1), - 'description' => 'Click this to download an a STIX2 document containing the STIX2 version of all events and attributes that you have access to.' + 'description' => 'Click this to download a STIX2 document containing the STIX2 version of all events and attributes that you have access to.' ), 'rpz' => array( 'extension' => '.txt', @@ -175,6 +183,7 @@ class Event extends AppModel 'text' => array('text', 'TextExport', 'txt'), 'csv' => array('csv', 'CsvExport', 'csv'), 'stix' => array('xml', 'Stix1Export', 'xml'), + 'stix-json' => array('json', 'Stix1Export', 'json'), 'stix2' => array('json', 'Stix2Export', 'json'), 'yara' => array('txt', 'YaraExport', 'yara'), 'yara-json' => array('json', 'YaraExport', 'json'), @@ -3171,7 +3180,7 @@ class Event extends AppModel $bodyevent = $temp[0]; $body = $temp[1]; $result = true; - $tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "TLP Amber"; + $tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "tlp:amber"; $subject = "[" . Configure::read('MISP.org') . " MISP] Need info about event " . $id . " - ".$tplColorString; $result = $this->User->sendEmail($reporter, $bodyevent, $body, $subject, $user) && $result; } diff --git a/app/Model/Post.php b/app/Model/Post.php index eac2a6b14..199450eec 100644 --- a/app/Model/Post.php +++ b/app/Model/Post.php @@ -118,7 +118,7 @@ class Post extends AppModel $bodyDetail .= "The following message was added: \n"; $bodyDetail .= "\n"; $bodyDetail .= $message . "\n"; - $tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "TLP Amber"; + $tplColorString = !empty(Configure::read('MISP.email_subject_TLP_string')) ? Configure::read('MISP.email_subject_TLP_string') : "tlp:amber"; $subject = "[" . Configure::read('MISP.org') . " MISP] New post in discussion " . $post['Post']['thread_id'] . " - ".$tplColorString; foreach ($orgMembers as $recipient) { $this->User->sendEmail($recipient, $bodyDetail, $body, $subject); diff --git a/app/Model/Server.php b/app/Model/Server.php index 2a6fd79bc..701d4bd75 100644 --- a/app/Model/Server.php +++ b/app/Model/Server.php @@ -134,7 +134,9 @@ class Server extends AppModel 'Push' => 'MISP/app/Console/cake Server push [user_id] [server_id]', 'Cache feeds for quick lookups' => 'MISP/app/Console/cake Server cacheFeed [user_id] [feed_id|all|csv|text|misp]', 'Fetch feeds as local data' => 'MISP/app/Console/cake Server fetchFeed [user_id] [feed_id|all|csv|text|misp]', - 'Run enrichment' => 'MISP/app/Console/cake Event enrichEvent [user_id] [event_id] [json_encoded_module_list]' + 'Run enrichment' => 'MISP/app/Console/cake Event enrichEvent [user_id] [event_id] [json_encoded_module_list]', + 'Test' => 'MISP/app/Console/cake Server test [server_id]', + 'List' => 'MISP/app/Console/cake Server list' ), 'description' => __('If you would like to automate tasks such as caching feeds or pulling from server instances, you can do it using the following command line tools. Simply execute the given commands via the command line / create cron jobs easily out of them.'), 'header' => __('Automating certain console tasks') @@ -428,7 +430,7 @@ class Server extends AppModel 'email_subject_TLP_string' => array( 'level' => 2, 'description' => __('This is the TLP string for e-mails when email_subject_tag is not found.'), - 'value' => 'TLP Amber', + 'value' => 'tlp:amber', 'errorMessage' => '', 'test' => 'testForEmpty', 'type' => 'string', @@ -2671,11 +2673,11 @@ class Server extends AppModel } elseif ("incremental" == $technique) { $eventid_conditions_key = 'Event.id >'; $eventid_conditions_value = $this->data['Server']['lastpushedid']; - } elseif (true == $technique) { + } elseif (intval($technique) !== 0) { $eventid_conditions_key = 'Event.id'; $eventid_conditions_value = intval($technique); } else { - $this->redirect(array('action' => 'index')); + throw new InvalidArgumentException("Technique parameter must be 'full', 'incremental' or event ID."); } $sgs = $this->Event->SharingGroup->find('all', array( 'recursive' => -1, @@ -2683,13 +2685,11 @@ class Server extends AppModel )); $sgIds = array(); foreach ($sgs as $k => $sg) { - if (!$this->Event->SharingGroup->checkIfServerInSG($sg, $this->data)) { - unset($sgs[$k]); - continue; + if ($this->Event->SharingGroup->checkIfServerInSG($sg, $this->data)) { + $sgIds[] = $sg['SharingGroup']['id']; } - $sgIds[] = $sg['SharingGroup']['id']; } - if (!isset($sgIds) || empty($sgIds)) { + if (empty($sgIds)) { $sgIds = array(-1); } $findParams = array( @@ -4338,7 +4338,7 @@ class Server extends AppModel public function stixDiagnostics(&$diagnostic_errors, &$stixVersion, &$cyboxVersion, &$mixboxVersion, &$maecVersion, &$stix2Version, &$pymispVersion) { $result = array(); - $expected = array('stix' => '>1.2.0.6', 'cybox' => '>2.1.0.18.dev0', 'mixbox' => '1.0.3', 'maec' => '>4.1.0.14', 'stix2' => '1.1.3', 'pymisp' => '>2.4.93'); + $expected = array('stix' => '>1.2.0.6', 'cybox' => '>2.1.0.18.dev0', 'mixbox' => '1.0.3', 'maec' => '>4.1.0.14', 'stix2' => '>1.2.0', 'pymisp' => '>2.4.93'); // check if the STIX and Cybox libraries are working using the test script stixtest.py $scriptResult = shell_exec($this->getPythonVersion() . ' ' . APP . 'files' . DS . 'scripts' . DS . 'stixtest.py'); $scriptResult = json_decode($scriptResult, true); diff --git a/app/Model/SharingGroup.php b/app/Model/SharingGroup.php index 6796b3f92..113740579 100644 --- a/app/Model/SharingGroup.php +++ b/app/Model/SharingGroup.php @@ -189,7 +189,11 @@ class SharingGroup extends AppModel 'conditions' => array('id' => $sg['SharingGroup']['org_id']) )); } - $sg['Organisation'] = $this->__sgoCache[$sg['SharingGroup']['org_id']]['Organisation']; + if(isset($this->__sgoCache[$sg['SharingGroup']['org_id']]['Organisation'])) { + $sg['Organisation'] = $this->__sgoCache[$sg['SharingGroup']['org_id']]['Organisation']; + } else { + $sg['Organisation'] = ''; + } if (!empty($sg['SharingGroupOrg'])) { foreach ($sg['SharingGroupOrg'] as &$sgo) { if (!isset($this->__sgoCache[$sgo['org_id']])) { diff --git a/app/Model/Taxonomy.php b/app/Model/Taxonomy.php index 5bc21a528..c987b176a 100644 --- a/app/Model/Taxonomy.php +++ b/app/Model/Taxonomy.php @@ -101,7 +101,7 @@ class Taxonomy extends AppModel } $this->deleteAll(array('Taxonomy.namespace' => $current['Taxonomy']['namespace'])); } - $taxonomy['Taxonomy'] = array('namespace' => $vocab['namespace'], 'description' => $vocab['description'], 'version' => $vocab['version'], 'enabled' => $enabled); + $taxonomy['Taxonomy'] = array('namespace' => $vocab['namespace'], 'description' => $vocab['description'], 'version' => $vocab['version'], 'exclusive' => $vocab['exclusive'], 'enabled' => $enabled); $predicateLookup = array(); foreach ($vocab['predicates'] as $k => $predicate) { $taxonomy['Taxonomy']['TaxonomyPredicate'][$k] = $predicate; @@ -489,27 +489,29 @@ class Taxonomy extends AppModel return $taxonomies; } - public function getTaxonomyForTag($tagName, $metaOnly = false) + public function getTaxonomyForTag($tagName, $metaOnly = false, $fullTaxonomy = False) { if (preg_match('/^[^:="]+:[^:="]+="[^:="]+"$/i', $tagName)) { $temp = explode(':', $tagName); $pieces = array_merge(array($temp[0]), explode('=', $temp[1])); $pieces[2] = trim($pieces[2], '"'); + $contain = array( + 'TaxonomyPredicate' => array( + 'TaxonomyEntry' => array() + ) + ); + if (!$fullTaxonomy) { + $contain['TaxonomyPredicate']['conditions'] = array( + 'LOWER(TaxonomyPredicate.value)' => strtolower($pieces[1]) + ); + $contain['TaxonomyPredicate']['TaxonomyEntry']['conditions'] = array( + 'LOWER(TaxonomyEntry.value)' => strtolower($pieces[2]) + ); + } $taxonomy = $this->find('first', array( 'recursive' => -1, 'conditions' => array('LOWER(Taxonomy.namespace)' => strtolower($pieces[0])), - 'contain' => array( - 'TaxonomyPredicate' => array( - 'conditions' => array( - 'LOWER(TaxonomyPredicate.value)' => strtolower($pieces[1]) - ), - 'TaxonomyEntry' => array( - 'conditions' => array( - 'LOWER(TaxonomyEntry.value)' => strtolower($pieces[2]) - ) - ) - ) - ) + 'contain' => $contain )); if ($metaOnly && !empty($taxonomy)) { return array('Taxonomy' => $taxonomy['Taxonomy']); @@ -517,16 +519,16 @@ class Taxonomy extends AppModel return $taxonomy; } elseif (preg_match('/^[^:="]+:[^:="]+$/i', $tagName)) { $pieces = explode(':', $tagName); + $contain = array('TaxonomyPredicate' => array()); + if (!$fullTaxonomy) { + $contain['TaxonomyPredicate']['conditions'] = array( + 'LOWER(TaxonomyPredicate.value)' => strtolower($pieces[1]) + ); + } $taxonomy = $this->find('first', array( 'recursive' => -1, 'conditions' => array('LOWER(Taxonomy.namespace)' => strtolower($pieces[0])), - 'contain' => array( - 'TaxonomyPredicate' => array( - 'conditions' => array( - 'LOWER(TaxonomyPredicate.value)' => strtolower($pieces[1]) - ) - ) - ) + 'contain' => $contain )); if ($metaOnly && !empty($taxonomy)) { return array('Taxonomy' => $taxonomy['Taxonomy']); @@ -536,4 +538,97 @@ class Taxonomy extends AppModel return false; } } + + // Remove the value for triple component tags or the predicate for double components tags + public function stripLastTagComponent($tagName) + { + $shortenedTag = ''; + if (preg_match('/^[^:="]+:[^:="]+="[^:="]+"$/i', $tagName)) { + $shortenedTag = explode('=', $tagName)[0]; + } elseif (preg_match('/^[^:="]+:[^:="]+$/i', $tagName)) { + $shortenedTag = explode(':', $tagName)[0]; + } + return $shortenedTag; + } + + public function checkIfNewTagIsAllowedByTaxonomy($newTagName, $tagNameList=array()) + { + $newTagShortened = $this->stripLastTagComponent($newTagName); + $prefixIsFree = true; + foreach ($tagNameList as $tagName) { + $tagShortened = $this->stripLastTagComponent($tagName); + if ($newTagShortened == $tagShortened) { + $prefixIsFree = false; + } + } + if (!$prefixIsFree) { + // at this point, we have a duplicated namespace(-predicate) + $taxonomy = $this->getTaxonomyForTag($newTagName); + if (!empty($taxonomy['Taxonomy']['exclusive'])) { + return false; // only one tag of this taxonomy is allowed + } elseif (!empty($taxonomy['TaxonomyPredicate'][0]['exclusive'])) { + return false; // only one tag belonging to this predicate is allowed + } + } + return true; + } + + public function checkIfTagInconsistencies($tagList) + { + $eventTags = array(); + $localEventTags = array(); + foreach($tagList as $tag) { + if ($tag['local'] == 0) { + $eventTags[] = $tag['Tag']['name']; + } else { + $localEventTags[] = $tag['Tag']['name']; + } + } + $tagConflicts = $this->getTagConflicts($eventTags); + $localTagConflicts = $this->getTagConflicts($localEventTags); + return array( + 'global' => $tagConflicts, + 'local' => $localTagConflicts + ); + } + + public function getTagConflicts($tagNameList) + { + $potentiallyConflictingTaxonomy = array(); + $conflictingTaxonomy = array(); + foreach ($tagNameList as $tagName) { + $tagShortened = $this->stripLastTagComponent($tagName); + if (isset($potentiallyConflictingTaxonomy[$tagShortened])) { + $potentiallyConflictingTaxonomy[$tagShortened]['taxonomy'] = $this->getTaxonomyForTag($tagName); + $potentiallyConflictingTaxonomy[$tagShortened]['count']++; + } else { + $potentiallyConflictingTaxonomy[$tagShortened] = array( + 'count' => 1 + ); + } + $potentiallyConflictingTaxonomy[$tagShortened]['tagNames'][] = $tagName; + } + foreach ($potentiallyConflictingTaxonomy as $potTaxonomy) { + if ($potTaxonomy['count'] > 1) { + $taxonomy = $potTaxonomy['taxonomy']; + if (isset($taxonomy['Taxonomy']['exclusive']) && $taxonomy['Taxonomy']['exclusive']) { + $conflictingTaxonomy[] = array( + 'tags' => $potTaxonomy['tagNames'], + 'taxonomy' => $taxonomy, + 'conflict' => sprintf(__('Taxonomy `%s` is an exclusive Taxonomy'), $taxonomy['Taxonomy']['namespace']) + ); + } elseif (isset($taxonomy['TaxonomyPredicate'][0]['exclusive']) && $taxonomy['TaxonomyPredicate'][0]['exclusive']) { + $conflictingTaxonomy[] = array( + 'tags' => $potTaxonomy['tagNames'], + 'taxonomy' => $taxonomy, + 'conflict' => sprintf( + __('Predicate `%s` is exclusive'), + $taxonomy['TaxonomyPredicate'][0]['value'] + ) + ); + } + } + } + return $conflictingTaxonomy; + } } diff --git a/app/Model/User.php b/app/Model/User.php index 183c05eb0..4e5e53563 100644 --- a/app/Model/User.php +++ b/app/Model/User.php @@ -609,7 +609,19 @@ class User extends AppModel throw new NotFoundException('Invalid user ID.'); } $conditions = array('User.id' => $id); - $user = $this->find('first', array('conditions' => $conditions, 'recursive' => -1,'contain' => array('Organisation', 'Role', 'Server'))); + $user = $this->find( + 'first', + array( + 'conditions' => $conditions, + 'recursive' => -1, + 'contain' => array( + 'Organisation', + 'Role', + 'Server', + 'UserSetting' + ) + ) + ); if (empty($user)) { return $user; } @@ -617,6 +629,7 @@ class User extends AppModel $user['User']['Role'] = $user['Role']; $user['User']['Organisation'] = $user['Organisation']; $user['User']['Server'] = $user['Server']; + $user['User']['UserSetting'] = $user['UserSetting']; unset($user['Organisation'], $user['Role'], $user['Server']); return $user['User']; } diff --git a/app/Model/UserSetting.php b/app/Model/UserSetting.php index 9d4de0497..c472185aa 100644 --- a/app/Model/UserSetting.php +++ b/app/Model/UserSetting.php @@ -45,6 +45,10 @@ class UserSetting extends AppModel ) ) ) + ), + 'dashboard_access' => array( + 'placeholder' => 1, + 'restricted' => 'perm_site_admin' ) ); @@ -56,7 +60,11 @@ class UserSetting extends AppModel if (empty($this->data['UserSetting']['timestamp'])) { $this->data['UserSetting']['timestamp'] = time(); } - if (!empty($this->data['UserSetting']['value']) && $this->data['UserSetting']['value'] !== 'null') { + if ( + isset($this->data['UserSetting']['value']) && + $this->data['UserSetting']['value'] !== '' && + $this->data['UserSetting']['value'] !== 'null' + ) { if (is_array($this->data['UserSetting']['value'])) { $this->data['UserSetting']['value'] = json_encode($this->data['UserSetting']['value']); } @@ -80,6 +88,29 @@ class UserSetting extends AppModel return isset($this->validSettings[$setting]); } + public function checkSettingAccess($user, $setting) + { + if (!empty($this->validSettings[$setting]['restricted'])) { + $role_check = $this->validSettings[$setting]['restricted']; + if (!is_array($role_check)) { + $role_check = array($role_check); + } + $userHasValidRole = false; + foreach ($role_check as $role) { + if (!empty($user['Role'][$role])) { + return true; + } + } + if (!$userHasValidRole) { + foreach ($role_check as &$role) { + $role = substr($role, 5); + } + return implode(', ', $role_check); + } + } + return true; + } + /* * canModify expects an auth user object or a user ID and a loaded setting as input parameters * check if the user can modify/remove the given entry diff --git a/app/View/Attributes/ajax/attributeViewFieldForm.ctp b/app/View/Attributes/ajax/attributeViewFieldForm.ctp index a00889a23..d40382a09 100644 --- a/app/View/Attributes/ajax/attributeViewFieldForm.ctp +++ b/app/View/Attributes/ajax/attributeViewFieldForm.ctp @@ -1,8 +1,8 @@ '; + echo ''; } else if ($value === 'Yes') { - echo ''; + echo ''; } else { echo nl2br(h($value)) . ' '; } diff --git a/app/View/Communities/view.ctp b/app/View/Communities/view.ctp index 7c5648a1e..1e21550a7 100644 --- a/app/View/Communities/view.ctp +++ b/app/View/Communities/view.ctp @@ -56,12 +56,3 @@ element('/genericElements/SideMenu/side_menu', array('menuList' => 'sync', 'menuItem' => 'view_community')); ?> - diff --git a/app/View/DecayingModel/decaying_tool.ctp b/app/View/DecayingModel/decaying_tool.ctp index 9ee6531c1..8098f55e7 100644 --- a/app/View/DecayingModel/decaying_tool.ctp +++ b/app/View/DecayingModel/decaying_tool.ctp @@ -5,21 +5,21 @@
- +
- + @@ -41,7 +41,7 @@ } ?> - +
@@ -85,17 +85,17 @@ ' . h($config['greek']).'' : ''); ?> - value= max= oninput="refreshGraph(this);" > - step= value= oninput="$('#input_').val(this.value).trigger('input');"> + value= max= oninput="refreshGraph(this);"> + step= value= oninput="$('#input_').val(this.value).trigger('input');"> - +
- + diff --git a/app/View/DecayingModel/decaying_tool_basescore.ctp b/app/View/DecayingModel/decaying_tool_basescore.ctp index e878967b7..0febdd1f0 100644 --- a/app/View/DecayingModel/decaying_tool_basescore.ctp +++ b/app/View/DecayingModel/decaying_tool_basescore.ctp @@ -1,11 +1,11 @@
- +
- +
@@ -49,8 +49,8 @@ @@ -77,8 +77,8 @@ diff --git a/app/View/Elements/Events/View/eventFilteringQueryBuilder.ctp b/app/View/Elements/Events/View/eventFilteringQueryBuilder.ctp index 1946389c3..ecf07c81d 100644 --- a/app/View/Elements/Events/View/eventFilteringQueryBuilder.ctp +++ b/app/View/Elements/Events/View/eventFilteringQueryBuilder.ctp @@ -1,7 +1,7 @@
- > + >
') - .append($('
- - + +
- - + +
- element('ajaxTags', array('attributeId' => $object['id'], 'tags' => $object['AttributeTag'], 'tagAccess' => ($isSiteAdmin || $mayModify || $me['org_id'] == $event['Event']['org_id']), 'context' => $context, 'scope' => 'attribute')); ?> + element('ajaxTags', array('attributeId' => $object['id'], 'tags' => $object['AttributeTag'], 'tagAccess' => ($isSiteAdmin || $mayModify || $me['org_id'] == $event['Event']['org_id']), 'context' => $context, 'scope' => 'attribute', 'tagConflicts' => isset($object['tagConflicts']) ? $object['tagConflicts'] : array())); ?>
diff --git a/app/View/Elements/Events/View/value_field.ctp b/app/View/Elements/Events/View/value_field.ctp index 177cab5e7..45bd36b51 100644 --- a/app/View/Elements/Events/View/value_field.ctp +++ b/app/View/Elements/Events/View/value_field.ctp @@ -5,7 +5,7 @@ switch ($object['type']) { case 'attachment': case 'malware-sample': if ($object['type'] === 'attachment' && isset($object['image'])) { - if (extension_loaded('gd')) { + if ($object['image'] === true) { $img = ''; $img .= ''; echo $img; @@ -24,7 +24,8 @@ switch ($object['type']) { $filename = $filenameHash[0]; } - $url = array('controller' => 'attributes', 'action' => 'download', $object['id']); + $controller = isset($object['objectType']) && $object['objectType'] === 'proposal' ? 'shadow_attributes' : 'attributes'; + $url = array('controller' => $controller, 'action' => 'download', $object['id']); echo $this->Html->link($filename, $url, array('class' => $linkClass)); if (isset($filenameHash[1])) { echo '
' . $filenameHash[1]; @@ -58,7 +59,7 @@ switch ($object['type']) { } else { $sigDisplay = str_replace("\r", '', h($sigDisplay)); $sigDisplay = str_replace(" ", ' ', $sigDisplay); - echo h($sigDisplay); + echo $sigDisplay; } break; diff --git a/app/View/Elements/Objects/object_similarities.ctp b/app/View/Elements/Objects/object_similarities.ctp index 7c824c39d..1b089ff43 100644 --- a/app/View/Elements/Objects/object_similarities.ctp +++ b/app/View/Elements/Objects/object_similarities.ctp @@ -86,7 +86,7 @@ if (!isset($simple_flattened_attribute_noval) || !isset($simple_flattened_attrib
- > + > diff --git a/app/View/Elements/ajaxTags.ctp b/app/View/Elements/ajaxTags.ctp index 3a4174c43..6a0c15255 100644 --- a/app/View/Elements/ajaxTags.ctp +++ b/app/View/Elements/ajaxTags.ctp @@ -162,4 +162,36 @@ '%s', $tagData ); + $tagConflictData = ''; + if (!empty($tagConflicts['global'])) { + $tagConflictData .= '
'; + $tagConflictData .= ''; + $tagConflictData .= '
'; + foreach ($tagConflicts['global'] as $tagConflict) { + $tagConflictData .= sprintf( + '%s
', + h($tagConflict['conflict']) + ); + foreach ($tagConflict['tags'] as $tag) { + $tagConflictData .= sprintf('%s
', h($tag)); + } + } + $tagConflictData .= '
'; + } + if (!empty($tagConflicts['local'])) { + $tagConflictData .= '
'; + $tagConflictData .= ''; + $tagConflictData .= '
'; + foreach ($tagConflicts['local'] as $tagConflict) { + $tagConflictData .= sprintf( + '%s
', + h($tagConflict['conflict']) + ); + foreach ($tagConflict['tags'] as $tag) { + $tagConflictData .= sprintf('%s
', h($tag)); + } + } + $tagConflictData .= '
'; + } + echo $tagConflictData; ?> diff --git a/app/View/Elements/eventattributetoolbar.ctp b/app/View/Elements/eventattributetoolbar.ctp index 57adc5438..279be0f29 100644 --- a/app/View/Elements/eventattributetoolbar.ctp +++ b/app/View/Elements/eventattributetoolbar.ctp @@ -100,7 +100,7 @@ 'id' => 'multi-accept-button', 'title' => __('Accept selected Proposals'), 'class' => 'mass-proposal-select hidden', - 'fa-icon' => 'check-circl', + 'fa-icon' => 'check-circle', 'onClick' => 'multiSelectAction', 'onClickParams' => array($event['Event']['id'], 'acceptProposals') ), diff --git a/app/View/Elements/galaxyQuickView.ctp b/app/View/Elements/galaxyQuickView.ctp index 2114f7864..3b8d403b0 100755 --- a/app/View/Elements/galaxyQuickView.ctp +++ b/app/View/Elements/galaxyQuickView.ctp @@ -151,9 +151,5 @@ $(this).parent().children('.collapse-status-container').children('.collapse-status').html('+'); } }); - $('.delete-cluster').click(function() { - var tagName = $(this).data('tag-name'); - removeTag($id = false, $tag_id = false, $galaxy = false); - }); }); diff --git a/app/View/Elements/galaxyQuickViewMini.ctp b/app/View/Elements/galaxyQuickViewMini.ctp index b5203b499..7328cc009 100644 --- a/app/View/Elements/galaxyQuickViewMini.ctp +++ b/app/View/Elements/galaxyQuickViewMini.ctp @@ -146,9 +146,5 @@ $(document).ready(function () { $(this).children('span').html('+'); } }); - $('.delete-cluster').click(function() { - var tagName = $(this).data('tag-name'); - removeTag($id = false, $tag_id = false, $galaxy = false); - }); }); diff --git a/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp b/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp index d6431dca6..db78fbfbf 100644 --- a/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp +++ b/app/View/Elements/genericElements/IndexTable/Fields/generic_field.ctp @@ -1,3 +1,11 @@ 1) { + $data = implode(', ', $data); + } else { + $data = $data[0]; + } + } + echo h($data); ?> diff --git a/app/View/Elements/genericElements/IndexTable/Fields/json.ctp b/app/View/Elements/genericElements/IndexTable/Fields/json.ctp index 3683a959f..9fe805c9d 100644 --- a/app/View/Elements/genericElements/IndexTable/Fields/json.ctp +++ b/app/View/Elements/genericElements/IndexTable/Fields/json.ctp @@ -1,5 +1,9 @@
', h($k) diff --git a/app/View/Elements/genericElements/ListTopBar/element_embedded.ctp b/app/View/Elements/genericElements/ListTopBar/element_embedded.ctp index 7e7026311..a3b540bc2 100644 --- a/app/View/Elements/genericElements/ListTopBar/element_embedded.ctp +++ b/app/View/Elements/genericElements/ListTopBar/element_embedded.ctp @@ -33,7 +33,7 @@ '
  • %s%s%s
  • ', empty($data['class']) ? '' : h($data['class']), empty($data['active']) ? '' : 'background-blue', // Change the default class for highlighted/active toggles here - empty($data['id']) ? '' : 'id="' . h($data['id']) . '"', + empty($data['id']) ? '' : h($data['id']), empty($data['url']) ? '#' : h($data['url']), // prevent default is passed if the url is not set empty($onClick) ? '' : $onClick, // pass $data['onClick'] for the function name to call and $data['onClickParams'] for the parameter list empty($dataFields) ? '' : $dataFields, diff --git a/app/View/Elements/serverRuleElements/pull.ctp b/app/View/Elements/serverRuleElements/pull.ctp index a38cd9ba4..bb478418f 100755 --- a/app/View/Elements/serverRuleElements/pull.ctp +++ b/app/View/Elements/serverRuleElements/pull.ctp @@ -15,7 +15,7 @@ >>
    - + << @@ -44,7 +44,7 @@ >> - + << diff --git a/app/View/Elements/view_galaxy_matrix.ctp b/app/View/Elements/view_galaxy_matrix.ctp index e7ee13a9f..d3cb7baee 100644 --- a/app/View/Elements/view_galaxy_matrix.ctp +++ b/app/View/Elements/view_galaxy_matrix.ctp @@ -88,7 +88,7 @@ foreach($tabs as $tabName => $column): - + diff --git a/app/View/Events/ajax/ajaxTags.ctp b/app/View/Events/ajax/ajaxTags.ctp index 6001997d0..e56be1370 100644 --- a/app/View/Events/ajax/ajaxTags.ctp +++ b/app/View/Events/ajax/ajaxTags.ctp @@ -6,6 +6,7 @@ echo $this->element('ajaxTags', array( 'event' => $event, 'tags' => $tags, - 'tagAccess' => ($isSiteAdmin || $mayModify) + 'tagAccess' => ($isSiteAdmin || $mayModify), + 'tagConflicts' => $tagConflicts )); ?> diff --git a/app/View/Events/upload_analysis_file.ctp b/app/View/Events/upload_analysis_file.ctp index d6268f651..eafd597cd 100644 --- a/app/View/Events/upload_analysis_file.ctp +++ b/app/View/Events/upload_analysis_file.ctp @@ -229,7 +229,7 @@ function processString(text) } $("#individualLines").find('tbody') .append($('
    ').html('')) + .append($('').html('')) .append($('').text(filepath)) .append($('').text(size)) .append($('').text(activity)) diff --git a/app/View/Events/view.ctp b/app/View/Events/view.ctp index 96fbf99cb..92dede70d 100644 --- a/app/View/Events/view.ctp +++ b/app/View/Events/view.ctp @@ -133,7 +133,8 @@ 'event' => $event, 'tags' => $event['EventTag'], 'tagAccess' => ($isSiteAdmin || $mayModify || $me['org_id'] == $event['Event']['orgc_id']), - 'required_taxonomies' => $required_taxonomies + 'required_taxonomies' => $required_taxonomies, + 'tagConflicts' => $tagConflicts ) ) ) @@ -197,7 +198,7 @@ ); $table_data[] = array( 'key' => __('First recorded change'), - 'value' => date('Y-m-d H:i:s', $oldest_timestamp) + 'value' => (!$oldest_timestamp) ? '' : date('Y-m-d H:i:s', $oldest_timestamp) ); $table_data[] = array( 'key' => __('Last change'), @@ -330,6 +331,41 @@ element('genericElements/viewMetaTable', array('table_data' => $table_data)); ?> diff --git a/app/View/Helper/FontAwesomeHelper.php b/app/View/Helper/FontAwesomeHelper.php index 34e806956..521f7f56a 100644 --- a/app/View/Helper/FontAwesomeHelper.php +++ b/app/View/Helper/FontAwesomeHelper.php @@ -446,4 +446,3 @@ App::uses('AppHelper', 'View/Helper'); } } } -?> diff --git a/app/View/Helper/GenericPickerHelper.php b/app/View/Helper/GenericPickerHelper.php index 36b30b210..9f9fe14f1 100644 --- a/app/View/Helper/GenericPickerHelper.php +++ b/app/View/Helper/GenericPickerHelper.php @@ -113,4 +113,3 @@ class GenericPickerHelper extends AppHelper { return $template; } } -?> diff --git a/app/View/Helper/HighlightHelper.php b/app/View/Helper/HighlightHelper.php index d47d17be3..571cb460e 100644 --- a/app/View/Helper/HighlightHelper.php +++ b/app/View/Helper/HighlightHelper.php @@ -40,4 +40,3 @@ App::uses('AppHelper', 'View/Helper'); } } -?> diff --git a/app/View/Helper/OrgImgHelper.php b/app/View/Helper/OrgImgHelper.php index 2a6cac1f5..5482287f5 100644 --- a/app/View/Helper/OrgImgHelper.php +++ b/app/View/Helper/OrgImgHelper.php @@ -58,4 +58,3 @@ App::uses('AppHelper', 'View/Helper'); } } } -?> diff --git a/app/View/Helper/PivotHelper.php b/app/View/Helper/PivotHelper.php index 56227c672..8918f747d 100644 --- a/app/View/Helper/PivotHelper.php +++ b/app/View/Helper/PivotHelper.php @@ -80,5 +80,3 @@ App::uses('AppHelper', 'View/Helper'); return $height + $heightToAdd; } } - -?> diff --git a/app/View/Helper/TextColourHelper.php b/app/View/Helper/TextColourHelper.php index 1a80ab2c0..aacfb0e91 100644 --- a/app/View/Helper/TextColourHelper.php +++ b/app/View/Helper/TextColourHelper.php @@ -17,4 +17,3 @@ App::uses('AppHelper', 'View/Helper'); } } } -?> diff --git a/app/View/Helper/UserNameHelper.php b/app/View/Helper/UserNameHelper.php index f21f04f08..3ba628bb3 100644 --- a/app/View/Helper/UserNameHelper.php +++ b/app/View/Helper/UserNameHelper.php @@ -21,4 +21,3 @@ App::uses('AppHelper', 'View/Helper'); return ''; } } -?> diff --git a/app/View/Helper/UtilityHelper.php b/app/View/Helper/UtilityHelper.php index b4194abb6..7ddd7490e 100644 --- a/app/View/Helper/UtilityHelper.php +++ b/app/View/Helper/UtilityHelper.php @@ -9,4 +9,4 @@ App::uses('AppHelper', 'View/Helper'); return $string; } } -?> + diff --git a/app/View/Helper/XmlOutputHelper.php b/app/View/Helper/XmlOutputHelper.php index b34169b6d..2f80d237a 100644 --- a/app/View/Helper/XmlOutputHelper.php +++ b/app/View/Helper/XmlOutputHelper.php @@ -22,4 +22,3 @@ App::uses('AppHelper', 'View/Helper'); } } } -?> diff --git a/app/View/Organisations/ajax/sg_org_row_empty.ctp b/app/View/Organisations/ajax/sg_org_row_empty.ctp index 51aab6194..ea915dfe0 100644 --- a/app/View/Organisations/ajax/sg_org_row_empty.ctp +++ b/app/View/Organisations/ajax/sg_org_row_empty.ctp @@ -7,7 +7,7 @@ $checked = ''; if ($extend) $checked = 'checked'; ?> - + diff --git a/app/View/SharingGroups/add.ctp b/app/View/SharingGroups/add.ctp index 54f3871e9..b3ec48e3d 100644 --- a/app/View/SharingGroups/add.ctp +++ b/app/View/SharingGroups/add.ctp @@ -49,13 +49,13 @@ ?>
    - + - +
    - +
    @@ -79,7 +79,7 @@
    >>
    diff --git a/app/View/UserSettings/index.ctp b/app/View/UserSettings/index.ctp index 9035f7c6c..6881781d8 100644 --- a/app/View/UserSettings/index.ctp +++ b/app/View/UserSettings/index.ctp @@ -69,6 +69,11 @@ 'sort' => 'type', 'element' => 'json', 'data_path' => 'UserSetting.value' + ), + array( + 'name' => __('Restricted to'), + 'sort' => 'type', + 'data_path' => 'UserSetting.restricted' ) ), 'title' => __('User settings management'), diff --git a/app/View/UserSettings/set_setting.ctp b/app/View/UserSettings/set_setting.ctp index 633786201..dffa2fd8f 100644 --- a/app/View/UserSettings/set_setting.ctp +++ b/app/View/UserSettings/set_setting.ctp @@ -19,7 +19,9 @@ array( 'div' => 'clear', 'class' => 'input input-xxlarge', - 'options' => array_combine(array_keys($validSettings), array_keys($validSettings)) + 'options' => array_combine(array_keys($validSettings), array_keys($validSettings)), + 'default' => $setting, + 'disabled' => (boolean)$setting ) ), $this->Form->input( diff --git a/app/View/Users/statistics_galaxymatrix.ctp b/app/View/Users/statistics_galaxymatrix.ctp index 8612e5c1c..248cc0aa5 100644 --- a/app/View/Users/statistics_galaxymatrix.ctp +++ b/app/View/Users/statistics_galaxymatrix.ctp @@ -24,9 +24,9 @@
    - + - +
    diff --git a/app/files/feed-metadata/defaults.json b/app/files/feed-metadata/defaults.json index b946ca218..c9497e4b2 100644 --- a/app/files/feed-metadata/defaults.json +++ b/app/files/feed-metadata/defaults.json @@ -29,7 +29,7 @@ "id": "2", "name": "The Botvrij.eu Data", "provider": "Botvrij.eu", - "url": "http://www.botvrij.eu/data/feed-osint", + "url": "https://www.botvrij.eu/data/feed-osint", "rules": "{\"tags\":{\"OR\":[],\"NOT\":[]},\"orgs\":{\"OR\":[],\"NOT\":[]}}", "enabled": true, "distribution": "3", @@ -1969,5 +1969,41 @@ "force_to_ids": false, "cache_timestamp": "1568901075" } + }, + { + "Feed": { + "id": "115", + "name": "Metasploit exploits with CVE assigned", + "provider": "eCrimeLabs", + "url": "https:\/\/feeds.ecrimelabs.net\/data\/metasploit-cve", + "rules": "{\"tags\":{\"OR\":[],\"NOT\":[]},\"orgs\":{\"OR\":[],\"NOT\":[]}}", + "enabled": true, + "distribution": "0", + "sharing_group_id": "0", + "tag_id": "0", + "default": false, + "source_format": "csv", + "fixed_event": true, + "delta_merge": true, + "event_id": "", + "publish": true, + "override_ids": false, + "settings": "{\"csv\":{\"value\":\"\",\"delimiter\":\",\"},\"common\":{\"excluderegex\":\"\"}}", + "input_source": "network", + "delete_local_file": false, + "lookup_visible": true, + "headers": "", + "caching_enabled": true, + "force_to_ids": false, + "cache_timestamp": "1571206806" + }, + "Tag": { + "id": "615", + "name": "osint:source-type=\"block-or-filter-list\"", + "colour": "#004577", + "exportable": true, + "org_id": "0", + "hide_tag": false + } } ] diff --git a/app/files/misp-galaxy b/app/files/misp-galaxy index ac8236d16..64a356980 160000 --- a/app/files/misp-galaxy +++ b/app/files/misp-galaxy @@ -1 +1 @@ -Subproject commit ac8236d16dca06076150fc9d6e7ec544645a676f +Subproject commit 64a35698033c471f0aebb375fe4d08addede8227 diff --git a/app/files/misp-objects b/app/files/misp-objects index ffc120106..58d6722f5 160000 --- a/app/files/misp-objects +++ b/app/files/misp-objects @@ -1 +1 @@ -Subproject commit ffc120106c4ba9ed3b2fd5ae18d41f730e61b3ab +Subproject commit 58d6722f5e276a0ec5889e6e67316b7401960542 diff --git a/app/files/scripts/generate_file_objects.py b/app/files/scripts/generate_file_objects.py index 73ecfd4b6..5aa74715b 100644 --- a/app/files/scripts/generate_file_objects.py +++ b/app/files/scripts/generate_file_objects.py @@ -5,7 +5,7 @@ import argparse import json try: - from pymisp import MISPEncode + from pymisp import pymisp_json_default from pymisp.tools import make_binary_objects except ImportError: pass @@ -51,7 +51,7 @@ def make_objects(path): to_return['objects'].append(fo) if fo.ObjectReference: to_return['references'] += fo.ObjectReference - return json.dumps(to_return, cls=MISPEncode) + return json.dumps(to_return, default=pymisp_json_default) if __name__ == '__main__': diff --git a/app/files/scripts/stix2/stix2misp.py b/app/files/scripts/stix2/stix2misp.py index fc7e1e2cb..c5103126c 100644 --- a/app/files/scripts/stix2/stix2misp.py +++ b/app/files/scripts/stix2/stix2misp.py @@ -48,9 +48,25 @@ class StixParser(): def load_data(self, filename, version, event, args): self.filename = filename self.stix_version = version - for object_type in special_parsing: - setattr(self, object_type.replace('-', '_'), event.pop(object_type) if object_type in event else {}) - self.event = event + self.event = defaultdict(dict) + self.event['relationship'] = defaultdict(list) + mapping = {'custom_object': self.__load_custom, + 'marking-definition': self.__load_marking, + 'relationship': self.__load_relationship, + 'report': self.__load_report} + mapping.update({object_type: self.__load_usual_object for object_type in ('indicator', 'observed-data', 'vulnerability', 'course-of-action')}) + mapping.update({galaxy_type: self.__load_galaxy for galaxy_type in galaxy_types}) + for parsed_object in event.objects: + try: + object_type = parsed_object._type + except AttributeError: + object_type = parsed_object['type'] + if object_type.startswith('x-misp-object'): + object_type = 'custom_object' + try: + mapping[object_type](parsed_object) + except KeyError: + self.__load_usual_object(parsed_object) try: event_distribution = args[0] if not isinstance(event_distribution, int): @@ -68,23 +84,56 @@ class StixParser(): self.misp_event.distribution = event_distribution self._attribute_distribution = attribute_distribution + def __load_custom(self, parsed_object): + self.event['custom_object'][parsed_object['id'].split('--')[1]] = parsed_object + + def __load_galaxy(self, parsed_object): + try: + self.galaxy[parsed_object['id'].split('--')[1]] = {'object': parsed_object, 'used': False} + except AttributeError: + self.galaxy = {parsed_object['id'].split('--')[1]: {'object': parsed_object, 'used': False}} + + def __load_marking(self, parsed_object): + try: + self.marking_definition[parsed_object['id'].split('--')[1]] = {'object': parsed_object, 'used': False} + except AttributeError: + self.marking_definition = {parsed_object['id'].split('--')[1]: {'object': parsed_object, 'used': False}} + + def __load_relationship(self, parsed_object): + try: + self.relationship[parsed_object.source_ref.split('--')[1]].append(parsed_object) + except AttributeError: + self.relationship = defaultdict(list) + self.relationship[parsed_object.source_ref.split('--')[1]].append(parsed_object) + + def __load_report(self, parsed_object): + try: + self.report[parsed_object['id'].split('--')[1]] = parsed_object + except AttributeError: + self.report = {parsed_object['id'].split('--')[1]: parsed_object} + + def __load_usual_object(self, parsed_object): + self.event[parsed_object._type][parsed_object['id'].split('--')[1]] = parsed_object + def general_handler(self): self.outputname = '{}.stix2'.format(self.filename) - self.build_from_STIX_with_report() if self.report else self.build_from_STIX_without_report() + self.build_from_STIX_with_report() if hasattr(self, 'report') else self.build_from_STIX_without_report() self.set_distribution() - for galaxy in self.galaxy.values(): - if galaxy['used'] == False: - self.misp_event['Galaxy'].append(self.parse_galaxies(galaxy['object'])) - for marking in self.marking_definition.values(): - if marking['used'] == False: - try: - self.misp_event.add_tag(self.parse_marking(marking['object'])) - except PyMISPInvalidFormat: - continue + if hasattr(self, 'galaxy'): + for galaxy in self.galaxy.values(): + if galaxy['used'] == False: + self.misp_event['Galaxy'].append(self.parse_galaxies(galaxy['object'])) + if hasattr(self, 'marking_definition'): + for marking in self.marking_definition.values(): + if marking['used'] == False: + try: + self.misp_event.add_tag(self.parse_marking(marking['object'])) + except PyMISPInvalidFormat: + continue def build_from_STIX_with_report(self): report_attributes = defaultdict(set) - for report in self.report.values(): + for ruuid, report in self.report.items(): try: report_attributes['orgs'].add(report.created_by_ref.split('--')[1]) except AttributeError: @@ -99,8 +148,11 @@ class StixParser(): for ref in report.object_refs: object_type, uuid = ref.split('--') if object_type not in special_parsing and object_type not in galaxy_types: - object2parse = self.event[object_type][uuid] - self.parsing_process(object2parse, object_type) + try: + object2parse = self.event[object_type][uuid] + self.parsing_process(object2parse, object_type) + except KeyError: + continue if len(report_attributes['orgs']) == 1: identity = self.event['identity'][report_attributes['orgs'].pop()] self.misp_event['Org'] = {'name': identity['name']} @@ -115,7 +167,7 @@ class StixParser(): def build_from_STIX_without_report(self): for object_type, objects in self.event.items(): - for _, _object in objects.items(): + for _object in objects.values(): self.parsing_process(_object, object_type) self.misp_event.info = "Imported with MISP import script for {}.".format(self.stix_version) @@ -338,11 +390,13 @@ class StixParser(): return attributes @staticmethod - def extract_data_from_file(objects): + def split_file_observable(objects): data = None for value in objects.values(): if isinstance(value, stix2.Artifact): data = value.payload_bin + elif isinstance(value, stix2.Directory): + data = value elif isinstance(value, stix2.File): file = value return file, data @@ -520,7 +574,7 @@ class StixFromMISPParser(StixParser): 'WindowsPEBinaryFile': {'observable': self.observable_pe, 'pattern': self.pattern_pe}, 'x509': {'observable': self.attributes_from_x509_observable, 'pattern': self.pattern_x509}} self.object_from_refs = {'course-of-action': self.parse_MISP_course_of_action, 'vulnerability': self.parse_vulnerability, - 'x-misp-object': self.parse_custom} + 'custom_object': self.parse_custom} self.object_from_refs.update(dict.fromkeys(['indicator', 'observed-data'], self.parse_usual_object)) self.attributes_fetcher_mapping = {'indicator': self.fetch_attributes_from_indicator, 'observed-data': self.fetch_attributes_from_observable, @@ -773,7 +827,7 @@ class StixFromMISPParser(StixParser): def observable_file(self, observable): if len(observable) > 1: - file, data = self.extract_data_from_file(observable) + file, data = self.split_file_observable(observable) if data is not None: return self.attributes_from_file_observable(file, data) return self.attributes_from_file_observable(observable['0']) @@ -1063,6 +1117,7 @@ class ExternalStixParser(StixParser): ('domain-name', 'ipv4-addr', 'ipv6-addr', 'network-traffic'): self.parse_ip_port_or_network_socket_observable, ('domain-name', 'network-traffic'): self.parse_network_socket_observable, ('domain-name', 'network-traffic', 'url'): self.parse_url_object_observable, + ('email-addr',): self.parse_email_address_observable, ('email-addr', 'email-message'): self.parse_email_observable, ('email-addr', 'email-message', 'file'): self.parse_email_observable, ('email-message',): self.parse_email_observable, @@ -1078,9 +1133,12 @@ class ExternalStixParser(StixParser): ('url',): self.parse_url_observable, ('user-account',): self.parse_user_account_observable, ('windows-registry-key',): self.parse_regkey_observable} - self.pattern_mapping = {('domain-name',): self.parse_domain_ip_port_pattern, + self.pattern_mapping = {('directory',): self.parse_file_pattern, + ('directory', 'file'): self.parse_file_pattern, + ('domain-name',): self.parse_domain_ip_port_pattern, ('domain-name', 'ipv4-addr', 'url'): self.parse_domain_ip_port_pattern, ('domain-name', 'ipv6-addr', 'url'): self.parse_domain_ip_port_pattern, + ('email-addr',): self.parse_email_address_pattern, ('file',): self.parse_file_pattern, ('ipv4-addr',): self.parse_ip_address_pattern, ('ipv6-addr',): self.parse_ip_address_pattern, @@ -1283,9 +1341,23 @@ class ExternalStixParser(StixParser): attributes.append(self.append_email_attribute(m_key, m_value, to_ids)) self.handle_import_case(attributes, 'email', marking, uuid) + def parse_email_address_observable(self, objects, marking, uuid): + mapping = to_attribute_mapping + attributes = [{'type': 'email-dst', 'object_relation': 'to', 'to_ids': True, 'value': _object.value} for _object in objects.values()] + self.handle_import_case(attributes, 'email', marking, uuid) + + def parse_email_address_pattern(self, pattern, marking=None, uuid=None): + pattern_types, pattern_values = self.get_types_and_values_from_pattern(pattern) + attributes = self.fill_pattern_attributes(pattern_types, pattern_values, email_mapping) + self.handle_import_case(attributes, 'email', marking, uuid) + def parse_file_observable(self, objects, marking, uuid): - _object = objects['0'] - attributes = self.attributes_from_file_observable(_object) + file, directory = self.split_file_observable(objects) + attributes = self.attributes_from_file_observable(file) + if directory is not None and directory.path: + mapping = file_mapping['path'] + attributes.append({'type': mapping['type'], 'object_relation': mapping['relation'], + 'value': directory.path, 'to_ids': False}) if hasattr(_object, 'extensions') and 'windows-pebinary-ext' in _object.extensions: self.handle_pe_case(_object.extensions['windows-pebinary-ext'], attributes, uuid) else: @@ -1294,10 +1366,13 @@ class ExternalStixParser(StixParser): def parse_file_pattern(self, pattern, marking=None, uuid=None): pattern_types, pattern_values = self.get_types_and_values_from_pattern(pattern) attributes = self.attributes_from_file_pattern(pattern_types, pattern_values) - self.handle_import_case(attributes, 'file', marking, uuid) + if any((attribute['object_relation'] == 'path' for attribute in attributes)): + self.object_case_import(attributes, 'file', uuid) + else: + self.handle_import_case(attributes, 'file', marking, uuid) def parse_file_object_observable(self, objects, marking, uuid): - file, data = self.extract_data_from_file(objects) + file, data = self.split_file_observable(objects) attributes = self.attributes_from_file_observable(file, data) if hasattr(file, 'extensions') and 'windows-pebinary-ext' in file.extensions: self.handle_pe_case(file.extensions['windows-pebinary-ext'], attributes, uuid) @@ -1439,7 +1514,10 @@ class ExternalStixParser(StixParser): try: type_, value = p.split('=') except ValueError: - type_, value = p.split(' = ') + try: + type_, value = p.split(' = ') + except ValueError: + type_, value = p.split(' = \'') types.append(type_.strip()) values.append(value.strip().strip('\'')) return types, values @@ -1470,42 +1548,19 @@ class ExternalStixParser(StixParser): return "{}:{}".format(marking_type, getattr(marking.definition, marking_type)) -def from_misp(reports): - for _, o in reports.items(): - if 'misp:tool="misp2stix2"' in o.get('labels'): +def from_misp(stix_objects): + for o in stix_objects: + if o._type == "report" and 'misp:tool="misp2stix2"' in o.get('labels'): return True return False def main(args): - stix_event = defaultdict(dict) - stix_event['relationship'] = defaultdict(list) filename = os.path.join(os.path.dirname(args[0]), args[1]) with open(filename, 'rt', encoding='utf-8') as f: event = stix2.parse(f.read(), allow_custom=True, interoperability=True) - for parsed_object in event.objects: - try: - object_type = parsed_object._type - except AttributeError: - object_type = parsed_object['type'] - if object_type.startswith('x-misp-object'): - object_type = 'x-misp-object' - if object_type == 'relationship': - stix_event[object_type][parsed_object.source_ref.split('--')[1]].append(parsed_object) - else: - uuid = parsed_object['id'].split('--')[1] - if object_type in galaxy_types: - parsed_object = {'object': parsed_object, 'used': False} - object_type = 'galaxy' - elif object_type == 'marking-definition': - parsed_object = {'object': parsed_object, 'used': False} - # object_type = object_type - stix_event[object_type][uuid] = parsed_object - if not stix_event: - print(json.dumps({'success': 0, 'message': 'There is no valid STIX object to import'})) - sys.exit(1) stix_version = 'STIX {}'.format(event.get('spec_version')) - stix_parser = StixFromMISPParser() if from_misp(stix_event['report']) else ExternalStixParser() - stix_parser.load_data(filename, stix_version, stix_event, args[2:]) + stix_parser = StixFromMISPParser() if from_misp(event.objects) else ExternalStixParser() + stix_parser.load_data(filename, stix_version, event, args[2:]) stix_parser.handler() stix_parser.saveFile() print(1) diff --git a/app/files/scripts/stix2/stix2misp_mapping.py b/app/files/scripts/stix2/stix2misp_mapping.py index d8fc14dea..716bfd325 100644 --- a/app/files/scripts/stix2/stix2misp_mapping.py +++ b/app/files/scripts/stix2/stix2misp_mapping.py @@ -143,6 +143,7 @@ mime_type_attribute_mapping = {'type': 'mime-type', 'relation': 'mimetype'} modified_attribute_mapping = {'type': 'datetime', 'relation': 'last-modified'} number_sections_mapping = {'type': 'counter', 'relation': 'number-sections'} password_mapping = {'type': 'text', 'relation': 'password'} +path_attribute_mapping = {'type': 'text', 'relation': 'path'} pe_type_mapping = {'type': 'text', 'relation': 'type'} pid_attribute_mapping = {'type': 'text', 'relation': 'pid'} process_command_line_mapping = {'type': 'text', 'relation': 'command-line'} @@ -204,12 +205,15 @@ email_mapping = {'date': email_date_attribute_mapping, 'from_ref': from_attribute_mapping, 'email-message:from_ref': from_attribute_mapping, 'body_multipart': body_multipart_mapping, - 'email-message:body_multipart[*].body_raw_ref.name': body_multipart_mapping} + 'email-message:body_multipart[*].body_raw_ref.name': body_multipart_mapping, + 'email-addr:value': to_attribute_mapping} file_mapping = {'mime_type': mime_type_attribute_mapping, 'file:mime_type': mime_type_attribute_mapping, 'name': filename_attribute_mapping, 'file:name': filename_attribute_mapping, + 'path': path_attribute_mapping, + 'directory:path': path_attribute_mapping, 'size': size_attribute_mapping, 'file:size': size_attribute_mapping} @@ -257,13 +261,13 @@ process_mapping = {'name': process_name_mapping, 'process:child_refs': {'type': 'text', 'relation': 'child-pid'}} regkey_mapping = {'data': data_attribute_mapping, - 'windows-registry-key:data': data_attribute_mapping, + 'windows-registry-key:values.data': data_attribute_mapping, 'data_type': data_type_attribute_mapping, - 'windows-registry-key:data_type': data_type_attribute_mapping, + 'windows-registry-key:values.data_type': data_type_attribute_mapping, 'modified': modified_attribute_mapping, 'windows-registry-key:modified': modified_attribute_mapping, 'name': regkey_name_attribute_mapping, - 'windows-registry-key:name': regkey_name_attribute_mapping, + 'windows-registry-key:values.name': regkey_name_attribute_mapping, 'key': key_attribute_mapping, 'windows-registry-key:key': key_attribute_mapping, 'windows-registry-key:value': {'type': 'text', 'relation': 'hive'} diff --git a/app/files/taxonomies b/app/files/taxonomies index 33e55b6db..9b31f7d02 160000 --- a/app/files/taxonomies +++ b/app/files/taxonomies @@ -1 +1 @@ -Subproject commit 33e55b6db3dc73d9f877c8880c13f9f7685625ec +Subproject commit 9b31f7d02d21f7557435e28c2296e62c52f97e2f diff --git a/app/webroot/css/main.css b/app/webroot/css/main.css index 30f4d3707..ead322638 100644 --- a/app/webroot/css/main.css +++ b/app/webroot/css/main.css @@ -2467,3 +2467,33 @@ table tr:hover .down-expand-button { #notice_message { margin: 10px; } + +.tag-conflict-notice { + margin: 5px 0px; + padding-right: 14px; + position: relative; +} + +.tag-conflict-notice div.text-container { + overflow: auto; +} + +.attributeTagContainer .tag-conflict-notice { + max-width: 350px; + overflow: auto; +} + +.tag-conflict-notice .apply_css_arrow { + display: inline-block; + padding: 0px 6px; +} + +.tag-conflict-notice i.icon { + position: absolute; + padding: 3px; + right: 0px; + top: 0px; + background-color: #3b3b3b; + color: white; + border-radius: 3px; +} \ No newline at end of file diff --git a/app/webroot/js/action_table.js b/app/webroot/js/action_table.js index d3fe6aecd..96a45b5bb 100644 --- a/app/webroot/js/action_table.js +++ b/app/webroot/js/action_table.js @@ -247,7 +247,7 @@ class ActionTable { var td = document.createElement('td'); var btn = document.createElement('button'); btn.classList.add("btn", "btn-danger"); - btn.innerHTML = ''; + btn.innerHTML = ''; btn.type = "button"; btn.setAttribute('rowID', tr.id); if (that.row_action_button_style.tooltip !== undefined) { diff --git a/app/webroot/js/decayingTool.js b/app/webroot/js/decayingTool.js index d61f0ea06..58fa7b0e2 100644 --- a/app/webroot/js/decayingTool.js +++ b/app/webroot/js/decayingTool.js @@ -1017,7 +1017,7 @@ ModelTable.prototype = { } var is_row_selected = $('#saveForm #save-model-button').data('modelid') == model.DecayingModel.id; return cells_html = [ - this._gen_td('', 'DMCheckbox'), + this._gen_td('', 'DMCheckbox'), this._gen_td_link('/decayingModel/view/'+model.DecayingModel.id, this._h(model.DecayingModel.id), 'DMId'), this._gen_td( this._h(model.DecayingModel.name) + (model.DecayingModel.default ? '' : '') , diff --git a/app/webroot/js/event-graph.js b/app/webroot/js/event-graph.js index 192dcc351..c9c0399ed 100644 --- a/app/webroot/js/event-graph.js +++ b/app/webroot/js/event-graph.js @@ -1401,7 +1401,7 @@ class DataHandler { eventGraph.menu_filter.items["table_attr_value"].add_options("table_control_select_attr_value", available_object_references); } - fetch_data_and_update(stabilize, callback) { + fetch_data_and_update(stabilize, updateOnly, callback) { eventGraph.network_loading(true, loadingText_fetching); $.when(this.fetch_objects_template()).done(function() { var filtering_rules = eventGraph.get_filtering_rules(); @@ -1419,7 +1419,9 @@ class DataHandler { data: JSON.stringify( payload ), processData: false, success: function( data, textStatus, jQxhr ){ - eventGraph.reset_graphs(true); + if (updateOnly === undefined || updateOnly === false) { + eventGraph.reset_graphs(true); + } eventGraph.is_filtered = (filtering_rules.presence.length > 0 || filtering_rules.value.length > 0); eventGraph.first_draw = true; // update object state @@ -1574,7 +1576,8 @@ class MispInteraction { if (!that.can_create_reference(edgeData.from) || !that.can_be_referenced(edgeData.to)) { return; } - genericPopup('/objectReferences/add/'+edgeData.from, '#popover_form', function() { + var edgeFromId = edgeData.from.startsWith('o-') ? edgeData.from.substr(2) : edgeData.from; + genericPopup('/objectReferences/add/'+edgeFromId, '#popover_form', function() { $('#ObjectReferenceReferencedUuid').val(uuid); objectReferenceInput(); }); @@ -1639,6 +1642,7 @@ class MispInteraction { var selected_nodes = nodeData.nodes; for (var nodeID of selected_nodes) { var node = this.nodes.get(nodeID) + nodeID = nodeID.startsWith('o-') ? nodeID.substr(2) : nodeID; if (node.group.slice(0, 9) == "attribute") { deleteObject('attributes', 'delete', nodeID, scope_id); } else if (node.group == "object") { @@ -1651,6 +1655,7 @@ class MispInteraction { var that = mispInteraction; var id = nodeData.id var group = nodes.get(id).group; + id = id.startsWith('o-') ? id.substr(2) : id; if (group.slice(0, 9) == 'attribute') { simplePopup('/attributes/edit/'+id); } else if (group == 'object') { @@ -1863,7 +1868,7 @@ function genericPopupCallback(result) { // sucess and eventgraph is enabled if (result == "success" && dataHandler !== undefined) { mispInteraction.apply_callback(); - dataHandler.fetch_data_and_update(false); + dataHandler.fetch_data_and_update(false, true); } } @@ -1960,7 +1965,7 @@ function import_graph_from_json(data) { $('#checkbox_physics_enable').prop('checked', data.physics.enabled); // update data - dataHandler.fetch_data_and_update(false, function() { + dataHandler.fetch_data_and_update(false, false, function() { eventGraph.nodes.update(data.nodes); eventGraph.expand_previous_expansion(data.nodes); eventGraph.hiddenNode.clear(); @@ -2182,7 +2187,7 @@ $(document).on("keyup", function(evt) { }); eventGraph.update_scope(); -dataHandler.fetch_data_and_update(true, function() { +dataHandler.fetch_data_and_update(true, false, function() { var $select = $('#network-typeahead'); dataHandler.get_typeaheadData_search().forEach(function(element) { var $option = $(''); diff --git a/app/webroot/js/misp.js b/app/webroot/js/misp.js index d186b4073..2a9b14cfc 100644 --- a/app/webroot/js/misp.js +++ b/app/webroot/js/misp.js @@ -2872,7 +2872,7 @@ function sharingGroupPopulateOrganisations() { if (org.removable == 1) { html += ''; diff --git a/app/webroot/js/network-distribution-graph.js b/app/webroot/js/network-distribution-graph.js index ac43f3d39..3c13c92cc 100644 --- a/app/webroot/js/network-distribution-graph.js +++ b/app/webroot/js/network-distribution-graph.js @@ -258,7 +258,7 @@ var $div = '