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 @@ } ?> | |||
---|---|---|---|---|
+ |
-
+
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 @@
-
+
-
+
|