mirror of https://github.com/MISP/MISP
Merge branch 'develop' into add_simple_background_jobs
commit
35cf34fab2
|
@ -6,9 +6,9 @@ name: misp
|
|||
# events but only for the 2.4 and develop branches
|
||||
on:
|
||||
push:
|
||||
branches: [ 2.4, develop ]
|
||||
branches: [ 2.4, develop, misp-stix ]
|
||||
pull_request:
|
||||
branches: [ 2.4, develop ]
|
||||
branches: [ 2.4, develop, misp-stix ]
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
|
@ -200,10 +200,13 @@ jobs:
|
|||
pushd ./app/files/scripts/cti-python-stix2
|
||||
pip install .
|
||||
popd
|
||||
pushd ./app/files/scripts/python-stix
|
||||
pip install .
|
||||
popd
|
||||
pushd PyMISP
|
||||
pip install .[fileobjects,email]
|
||||
popd
|
||||
pip install stix zmq redis plyara
|
||||
pip install zmq redis plyara
|
||||
deactivate
|
||||
|
||||
- name: Test if apache is working
|
||||
|
|
|
@ -45,9 +45,6 @@ tools/mkdocs
|
|||
!/app/files/misp-objects/*
|
||||
!/app/files/misp-decaying-models
|
||||
!/app/files/misp-decaying-models/*
|
||||
/app/files/scripts/python-stix/
|
||||
/app/files/scripts/python-cybox/
|
||||
/app/files/scripts/mixbox/
|
||||
/app/files/scripts/*.pyc
|
||||
/app/files/scripts/*.py~
|
||||
/app/files/scripts/__pycache__
|
||||
|
|
|
@ -1403,6 +1403,9 @@ installCore () {
|
|||
sudo mkdir /var/www/.cache/
|
||||
sudo chown ${WWW_USER}:${WWW_USER} /var/www/.cache
|
||||
|
||||
# install python-stix dependencies
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
debug "Install PyMISP"
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ${PATH_TO_MISP}/PyMISP
|
||||
|
||||
|
@ -1725,6 +1728,9 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert_age" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert_by_date" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban_threshold" 5
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban_refresh_on_retry" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.incoming_tags_disabled_by_default" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.maintenance_message" "Great things are happening! MISP is undergoing maintenance, but will return shortly. You can contact the administration at \$email."
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.footermidleft" "This is an initial install"
|
||||
|
@ -2329,6 +2335,7 @@ installCoreRHEL7 () {
|
|||
cd $PATH_TO_MISP
|
||||
|
||||
# Fetch submodules
|
||||
$SUDO_WWW git submodule sync
|
||||
$SUDO_WWW git submodule update --init --recursive
|
||||
# Make git ignore filesystem permission differences for submodules
|
||||
$SUDO_WWW git submodule foreach --recursive git config core.filemode false
|
||||
|
@ -2347,6 +2354,9 @@ installCoreRHEL7 () {
|
|||
UMASK=$(umask)
|
||||
umask 0022
|
||||
|
||||
# install python-stix dependencies
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
# install zmq
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U zmq
|
||||
|
||||
|
@ -2458,6 +2468,9 @@ installCoreRHEL8 () {
|
|||
UMASK=$(umask)
|
||||
umask 0022
|
||||
|
||||
# install python-stix dependencies
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
# install zmq, redis
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U zmq redis
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
; Generated by RHash v1.4.2 on 2021-10-08 at 10:34.14
|
||||
; Generated by RHash v1.3.9 on 2021-10-18 at 10:56.53
|
||||
; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/
|
||||
;
|
||||
; 159470 10:34.13 2021-10-08 INSTALL.sh
|
||||
INSTALL.sh 9E3B4D450C3F35EEAA14547662979DF376549652 18C310BEC8A91335D8430C0C5B8AC7E60D9B3FFD0B8E3415CF4B32A10A1A6782 316CC204FB4FADA321923109797782A7CA41C258D5841A8A8396BBB3A06B21FEB0A1F37A11A4B6D4C7FEA6B060B1EAD8 967DBCCE0D1E26B2CF285C52625F4859395032B8F502A42FE32D9B3237172FDC4CAE2DC4B0AA9C23B4D278102EA58DE83BDB2760748B049816788395345B42A7
|
||||
; 160201 10:56.53 2021-10-18 INSTALL.sh
|
||||
INSTALL.sh 8F59974F7AE69DFBF7B1C492E35F0B421AAC10C1 6F9E9C2C24880D2E69E04AB6AE490F72D8B5CBE5BB98596F4FA50C1CFEAA632F CBCFBA692B57E027A9861C4D4FB1D4808511A23148516946802B0364D428638E60087AD6EA7E2F016B2F65CD216DE288 7221893A49C924974F7D28C094C6CB27FC8ACA6E07FECD7B8DE4D55D283C9D6A5FF63409F55EEC110BF6612E8578BD1373E39B83A7986A6369ACF32A6A92F538
|
||||
|
|
|
@ -1 +1 @@
|
|||
9e3b4d450c3f35eeaa14547662979df376549652 INSTALL.sh
|
||||
8f59974f7ae69dfbf7b1c492e35f0b421aac10c1 INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
18c310bec8a91335d8430c0c5b8ac7e60d9b3ffd0b8e3415cf4b32a10a1a6782 INSTALL.sh
|
||||
6f9e9c2c24880d2e69e04ab6ae490f72d8b5cbe5bb98596f4fa50c1cfeaa632f INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
316cc204fb4fada321923109797782a7ca41c258d5841a8a8396bbb3a06b21feb0a1f37a11a4b6d4c7fea6b060b1ead8 INSTALL.sh
|
||||
cbcfba692b57e027a9861c4d4fb1d4808511a23148516946802b0364d428638e60087ad6ea7e2f016b2f65cd216de288 INSTALL.sh
|
||||
|
|
|
@ -1 +1 @@
|
|||
967dbcce0d1e26b2cf285c52625f4859395032b8f502a42fe32d9b3237172fdc4cae2dc4b0aa9c23b4d278102ea58de83bdb2760748b049816788395345b42a7 INSTALL.sh
|
||||
7221893a49c924974f7d28c094c6cb27fc8aca6e07fecd7b8de4d55d283c9d6a5ff63409f55eec110bf6612e8578bd1373e39b83a7986a6369acf32a6a92f538 INSTALL.sh
|
||||
|
|
|
@ -1056,6 +1056,7 @@ CREATE TABLE IF NOT EXISTS `sharing_groups` (
|
|||
INDEX `org_id` (`org_id`),
|
||||
INDEX `sync_user_id` (`sync_user_id`),
|
||||
UNIQUE INDEX `uuid` (`uuid`),
|
||||
UNIQUE INDEX `name` (`name`),
|
||||
INDEX `organisation_uuid` (`organisation_uuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
|
||||
|
||||
|
|
|
@ -447,7 +447,7 @@ class EventShell extends AppShell
|
|||
public function publish_galaxy_clusters()
|
||||
{
|
||||
$this->ConfigLoad->execute();
|
||||
if (empty($this->args[0]) || empty($this->args[1]) || empty($this->args[2]) || empty($this->args[3])) {
|
||||
if (empty($this->args[0]) || empty($this->args[1]) || empty($this->args[2]) || !array_key_exists(3, $this->args)) {
|
||||
die('Usage: ' . $this->Server->command_line_functions['event_management_tasks']['data']['Publish Galaxy clusters'] . PHP_EOL);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,28 +82,31 @@ class UserShell extends AppShell
|
|||
|
||||
public function list()
|
||||
{
|
||||
// do not fetch sensitive or big values
|
||||
$schema = $this->User->schema();
|
||||
unset($schema['authkey']);
|
||||
unset($schema['password']);
|
||||
unset($schema['gpgkey']);
|
||||
unset($schema['certif_public']);
|
||||
|
||||
$fields = array_keys($schema);
|
||||
$fields[] = 'Role.*';
|
||||
$fields[] = 'Organisation.*';
|
||||
|
||||
$users = $this->User->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => $fields,
|
||||
'contain' => ['Organisation', 'Role'],
|
||||
]);
|
||||
|
||||
if ($this->params['json']) {
|
||||
// do not fetch sensitive or big values
|
||||
$schema = $this->User->schema();
|
||||
unset($schema['authkey']);
|
||||
unset($schema['password']);
|
||||
unset($schema['gpgkey']);
|
||||
unset($schema['certif_public']);
|
||||
|
||||
$fields = array_keys($schema);
|
||||
$fields[] = 'Role.*';
|
||||
$fields[] = 'Organisation.*';
|
||||
|
||||
$users = $this->User->find('all', [
|
||||
'recursive' => -1,
|
||||
'fields' => $fields,
|
||||
'contain' => ['Organisation', 'Role', 'UserSetting'],
|
||||
]);
|
||||
|
||||
$this->out($this->json($users));
|
||||
} else {
|
||||
$users = $this->User->find('column', [
|
||||
'fields' => ['email'],
|
||||
]);
|
||||
foreach ($users as $user) {
|
||||
$this->out($user['User']['email']);
|
||||
$this->out($user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,12 +366,8 @@ class AppController extends Controller
|
|||
|
||||
// Notifications and homepage is not necessary for AJAX or REST requests
|
||||
if ($user && !$this->_isRest() && !$isAjax) {
|
||||
if ($this->request->params['controller'] === 'users' && $this->request->params['action'] === 'dashboard') {
|
||||
$notifications = $this->User->populateNotifications($user);
|
||||
} else {
|
||||
$notifications = $this->User->populateNotifications($user, 'fast');
|
||||
}
|
||||
$this->set('notifications', $notifications);
|
||||
$hasNotifications = $this->User->hasNotifications($user);
|
||||
$this->set('hasNotifications', $hasNotifications);
|
||||
|
||||
$homepage = $this->User->UserSetting->getValueForUser($user['id'], 'homepage');
|
||||
if (!empty($homepage)) {
|
||||
|
|
|
@ -2673,16 +2673,11 @@ class AttributesController extends AppController
|
|||
}
|
||||
}
|
||||
} else {
|
||||
$conditions = array('LOWER(Tag.name)' => strtolower(trim($tag_id)));
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
|
||||
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
|
||||
}
|
||||
$tag = $this->Attribute->AttributeTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
|
||||
if (empty($tag)) {
|
||||
$tagId = $this->Attribute->AttributeTag->Tag->lookupTagIdForUser($this->Auth->user(), trim($tag_id));
|
||||
if (empty($tagId)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
$tag_id = $tag['Tag']['id'];
|
||||
$tag_id = $tagId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,20 +28,22 @@ class EventsController extends AppController
|
|||
)
|
||||
);
|
||||
|
||||
private $acceptedFilteringNamedParams = array(
|
||||
'sort', 'direction', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'attributeFilter', 'extended', 'page',
|
||||
// private
|
||||
const ACCEPTED_FILTERING_NAMED_PARAMS = array(
|
||||
'sort', 'direction', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'attributeFilter', 'page',
|
||||
'searchFor', 'proposal', 'correlation', 'warning', 'deleted', 'includeRelatedTags', 'includeDecayScore', 'distribution',
|
||||
'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'focus', 'extended', 'overrideLimit',
|
||||
'filterColumnsOverwrite', 'feed', 'server', 'toIDS', 'sighting', 'includeSightingdb', 'warninglistId'
|
||||
'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'feed', 'server', 'toIDS',
|
||||
'sighting', 'includeSightingdb', 'warninglistId'
|
||||
);
|
||||
|
||||
public $defaultFilteringRules = array(
|
||||
// private
|
||||
const DEFAULT_FILTERING_RULE = array(
|
||||
'searchFor' => '',
|
||||
'attributeFilter' => 'all',
|
||||
'proposal' => 0,
|
||||
'correlation' => 0,
|
||||
'warning' => 0,
|
||||
'deleted' => 2,
|
||||
'deleted' => 0,
|
||||
'includeRelatedTags' => 0,
|
||||
'includeDecayScore' => 0,
|
||||
'toIDS' => 0,
|
||||
|
@ -700,7 +702,9 @@ class EventsController extends AppController
|
|||
$this->paginate['contain']['ThreatLevel'] = [
|
||||
'fields' => array('ThreatLevel.name')
|
||||
];
|
||||
$this->paginate['contain'][] = 'EventTag';
|
||||
$this->paginate['contain']['EventTag'] = [
|
||||
'fields' => ['EventTag.event_id', 'EventTag.tag_id', 'EventTag.local'],
|
||||
];
|
||||
if ($this->_isSiteAdmin()) {
|
||||
$this->paginate['contain'][] = 'User.email';
|
||||
}
|
||||
|
@ -1178,7 +1182,7 @@ class EventsController extends AppController
|
|||
{
|
||||
$filterData = array(
|
||||
'request' => $this->request,
|
||||
'paramArray' => $this->acceptedFilteringNamedParams,
|
||||
'paramArray' => self::ACCEPTED_FILTERING_NAMED_PARAMS,
|
||||
'named_params' => $this->request->params['named']
|
||||
);
|
||||
$exception = false;
|
||||
|
@ -1211,9 +1215,9 @@ class EventsController extends AppController
|
|||
if ($filters['deleted'] == 1) { // both
|
||||
$conditions['deleted'] = [0, 1];
|
||||
} elseif ($filters['deleted'] == 0) { // not-deleted only
|
||||
$conditions['deleted'] = 1;
|
||||
} else { // only deleted
|
||||
$conditions['deleted'] = 0;
|
||||
} else { // only deleted
|
||||
$conditions['deleted'] = 1;
|
||||
}
|
||||
}
|
||||
if (isset($filters['toIDS']) && $filters['toIDS'] != 0) {
|
||||
|
@ -1325,33 +1329,28 @@ class EventsController extends AppController
|
|||
}
|
||||
$this->params->params['paging'] = array($this->modelClass => $params);
|
||||
$this->set('event', $event);
|
||||
|
||||
$deleted = 0;
|
||||
if (isset($filters['deleted'])) {
|
||||
$deleted = $filters['deleted'] != 2 ? 1 : 0;
|
||||
}
|
||||
$this->set('includeSightingdb', (!empty($filters['includeSightingdb']) && Configure::read('Plugin.Sightings_sighting_db_enable')));
|
||||
$this->set('deleted', $deleted);
|
||||
$this->set('deleted', isset($filters['deleted']) && $filters['deleted'] != 0);
|
||||
$this->set('attributeFilter', isset($filters['attributeFilter']) ? $filters['attributeFilter'] : 'all');
|
||||
$this->set('filters', $filters);
|
||||
$advancedFiltering = $this->__checkIfAdvancedFiltering($filters);
|
||||
$this->set('advancedFilteringActive', $advancedFiltering['active'] ? 1 : 0);
|
||||
$this->set('advancedFilteringActiveRules', $advancedFiltering['activeRules']);
|
||||
$this->response->disableCache();
|
||||
$uriArray = explode('/', $this->params->here);
|
||||
|
||||
// Remove `focus` attribute from URI
|
||||
$uriArray = explode('/', $this->request->here);
|
||||
foreach ($uriArray as $k => $v) {
|
||||
if (strpos($v, ':')) {
|
||||
$temp = explode(':', $v);
|
||||
if ($temp[0] == 'focus') {
|
||||
unset($uriArray[$k]);
|
||||
}
|
||||
if (strpos($v, 'focus:') === 0) {
|
||||
unset($uriArray[$k]);
|
||||
}
|
||||
$this->params->here = implode('/', $uriArray);
|
||||
$this->request->here = implode('/', $uriArray);
|
||||
}
|
||||
|
||||
if (!empty($filters['includeSightingdb']) && Configure::read('Plugin.Sightings_sighting_db_enable')) {
|
||||
$this->set('sightingdbs', $this->Sightingdb->getSightingdbList($this->Auth->user()));
|
||||
}
|
||||
$this->set('currentUri', $this->params->here);
|
||||
$this->set('currentUri', $this->request->here);
|
||||
$this->layout = false;
|
||||
$this->__eventViewCommon($this->Auth->user());
|
||||
$this->render('/Elements/eventattribute');
|
||||
|
@ -1368,7 +1367,7 @@ class EventsController extends AppController
|
|||
$this->loadModel('Taxonomy');
|
||||
$filterData = array(
|
||||
'request' => $this->request,
|
||||
'paramArray' => $this->acceptedFilteringNamedParams,
|
||||
'paramArray' => self::ACCEPTED_FILTERING_NAMED_PARAMS,
|
||||
'named_params' => $this->request->params['named']
|
||||
);
|
||||
$exception = false;
|
||||
|
@ -1588,7 +1587,7 @@ class EventsController extends AppController
|
|||
|
||||
private function __eventViewCommon(array $user)
|
||||
{
|
||||
$this->set('defaultFilteringRules', $this->defaultFilteringRules);
|
||||
$this->set('defaultFilteringRules', self::DEFAULT_FILTERING_RULE);
|
||||
$this->set('typeGroups', array_keys($this->Event->Attribute->typeGroupings));
|
||||
|
||||
$orgTable = $this->Event->Orgc->find('list', array(
|
||||
|
@ -1663,20 +1662,18 @@ class EventsController extends AppController
|
|||
if (isset($this->request->data['deleted'])) {
|
||||
$deleted = $this->request->data['deleted'];
|
||||
}
|
||||
if (isset($deleted)) {
|
||||
// workaround for old instances trying to pull events with both deleted / non deleted data
|
||||
if (($this->userRole['perm_sync'] && $this->_isRest() && !$this->userRole['perm_site_admin']) && $deleted == 1) {
|
||||
$conditions['deleted'] = array(0, 1);
|
||||
} else {
|
||||
if (is_array($deleted)) {
|
||||
$conditions['deleted'] = $deleted;
|
||||
} else if ($deleted == 1) { // both
|
||||
$conditions['deleted'] = [0, 1];
|
||||
} elseif ($deleted == 0) { // not-deleted only
|
||||
$conditions['deleted'] = 0;
|
||||
} else { // only deleted
|
||||
$conditions['deleted'] = 1;
|
||||
}
|
||||
// workaround for old instances trying to pull events with both deleted / non deleted data
|
||||
if (($this->userRole['perm_sync'] && $this->_isRest() && !$this->userRole['perm_site_admin']) && $deleted == 1) {
|
||||
$conditions['deleted'] = array(0, 1);
|
||||
} else {
|
||||
if (is_array($deleted)) {
|
||||
$conditions['deleted'] = $deleted;
|
||||
} else if ($deleted == 1) { // both
|
||||
$conditions['deleted'] = [0, 1];
|
||||
} elseif ($deleted == 0) { // not-deleted only
|
||||
$conditions['deleted'] = 0;
|
||||
} else { // only deleted
|
||||
$conditions['deleted'] = 1;
|
||||
}
|
||||
}
|
||||
if (isset($namedParams['toIDS']) && $namedParams['toIDS'] != 0) {
|
||||
|
@ -1786,7 +1783,7 @@ class EventsController extends AppController
|
|||
return $this->__restResponse($event);
|
||||
}
|
||||
|
||||
$this->set('deleted', isset($deleted) ? ($deleted > 0 ? 1 : 0) : 0);
|
||||
$this->set('deleted', $deleted > 0);
|
||||
$this->set('includeRelatedTags', (!empty($namedParams['includeRelatedTags'])) ? 1 : 0);
|
||||
$this->set('includeDecayScore', (!empty($namedParams['includeDecayScore'])) ? 1 : 0);
|
||||
|
||||
|
@ -1996,7 +1993,7 @@ class EventsController extends AppController
|
|||
unset($filters['direction']);
|
||||
$activeRules = array();
|
||||
foreach ($filters as $k => $v) {
|
||||
if (isset($this->defaultFilteringRules[$k]) && $this->defaultFilteringRules[$k] != $v) {
|
||||
if (isset(self::DEFAULT_FILTERING_RULE[$k]) && self::DEFAULT_FILTERING_RULE[$k] != $v) {
|
||||
$activeRules[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
@ -2273,17 +2270,20 @@ class EventsController extends AppController
|
|||
}
|
||||
}
|
||||
|
||||
public function upload_stix($stix_version = '1')
|
||||
public function upload_stix($stix_version = '1', $publish = false)
|
||||
{
|
||||
if ($this->request->is('post')) {
|
||||
if ($this->_isRest()) {
|
||||
if (isset($this->params['named']['publish'])) {
|
||||
$publish = $this->params['named']['publish'];
|
||||
}
|
||||
$filePath = FileAccessTool::writeToTempFile($this->request->input());
|
||||
$result = $this->Event->upload_stix(
|
||||
$this->Auth->user(),
|
||||
$filePath,
|
||||
$stix_version,
|
||||
'uploaded_stix_file.' . ($stix_version == '1' ? 'xml' : 'json'),
|
||||
false
|
||||
$publish
|
||||
);
|
||||
if (is_numeric($result)) {
|
||||
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $result));
|
||||
|
@ -3467,16 +3467,11 @@ class EventsController extends AppController
|
|||
}
|
||||
}
|
||||
} else {
|
||||
$conditions = array('LOWER(Tag.name)' => strtolower(trim($tag_id)));
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
|
||||
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
|
||||
}
|
||||
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
|
||||
if (empty($tag)) {
|
||||
$tagId = $this->Event->EventTag->Tag->lookupTagIdForUser($this->Auth->user(), trim($tag_id));
|
||||
if (empty($tagId)) {
|
||||
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
|
||||
}
|
||||
$tag_id = $tag['Tag']['id'];
|
||||
$tag_id = $tagId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5661,13 +5656,13 @@ class EventsController extends AppController
|
|||
$objectRef['object_id'] = $ObjectResult;
|
||||
$objectRef['relationship_type'] = "preceded-by";
|
||||
$this->loadModel('MispObject');
|
||||
$result = $this->MispObject->ObjectReference->captureReference($objectRef, $eventId, $this->Auth->user(), false);
|
||||
$result = $this->MispObject->ObjectReference->captureReference($objectRef, $eventId);
|
||||
$objectRef['referenced_id'] = $temp['Object']['id'];
|
||||
$objectRef['referenced_uuid'] = $temp['Object']['uuid'];
|
||||
$objectRef['object_id'] = $PreviousObjRef['Object']['id'];
|
||||
$objectRef['relationship_type'] = "followed-by";
|
||||
$this->loadModel('MispObject');
|
||||
$result = $this->MispObject->ObjectReference->captureReference($objectRef, $eventId, $this->Auth->user(), false);
|
||||
$result = $this->MispObject->ObjectReference->captureReference($objectRef, $eventId);
|
||||
$PreviousObjRef = $temp;
|
||||
} else {
|
||||
$PreviousObjRef = $temp;
|
||||
|
|
|
@ -708,7 +708,7 @@ class ShadowAttributesController extends AppController
|
|||
}
|
||||
throw new InternalErrorException(__('Could not save the proposal. Errors: %s', $message));
|
||||
} else {
|
||||
$this->Flash->error(__('The ShadowAttribute could not be saved. Please, try again.'));
|
||||
$this->Flash->error(__('The proposed Attribute could not be saved. Please, try again.'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -44,7 +44,7 @@ class MispStatusWidget
|
|||
'View'
|
||||
)
|
||||
);
|
||||
$notifications = $this->Event->populateNotifications($user);
|
||||
$notifications = $this->Event->User->populateNotifications($user);
|
||||
if (!empty($notifications['proposalCount'])) {
|
||||
$data[] = array(
|
||||
'title' => __('Pending proposals'),
|
||||
|
|
|
@ -86,7 +86,8 @@ class AppModel extends Model
|
|||
51 => false, 52 => false, 53 => false, 54 => false, 55 => false, 56 => false,
|
||||
57 => false, 58 => false, 59 => false, 60 => false, 61 => false, 62 => false,
|
||||
63 => true, 64 => false, 65 => false, 66 => false, 67 => false, 68 => false,
|
||||
69 => false, 70 => false, 71 => true, 72 => true,
|
||||
69 => false, 70 => false, 71 => true, 72 => true, 73 => false, 74 => false,
|
||||
75 => false,
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1581,6 +1582,20 @@ class AppModel extends Model
|
|||
case 72:
|
||||
$sqlArray[] = "ALTER TABLE `auth_keys` ADD `read_only` tinyint(1) NOT NULL DEFAULT 0 AFTER `expiration`;";
|
||||
break;
|
||||
case 73:
|
||||
$this->__dropIndex('user_settings', 'timestamp'); // index is not used
|
||||
$sqlArray[] = "ALTER TABLE `user_settings` ADD UNIQUE INDEX `unique_setting` (`user_id`, `setting`)";
|
||||
break;
|
||||
case 74:
|
||||
$sqlArray[] = "ALTER TABLE `users` MODIFY COLUMN `change_pw` tinyint(1) NOT NULL DEFAULT 0;";
|
||||
break;
|
||||
case 75:
|
||||
$this->__addIndex('object_references', 'event_id');
|
||||
$this->__dropIndex('object_references', 'timestamp');
|
||||
$this->__dropIndex('object_references', 'source_uuid');
|
||||
$this->__dropIndex('object_references', 'relationship_type');
|
||||
$this->__dropIndex('object_references', 'referenced_uuid');
|
||||
break;
|
||||
case 'fixNonEmptySharingGroupID':
|
||||
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
|
||||
|
@ -2423,60 +2438,6 @@ class AppModel extends Model
|
|||
return true;
|
||||
}
|
||||
|
||||
public function populateNotifications($user, $mode = 'full')
|
||||
{
|
||||
$notifications = array();
|
||||
list($notifications['proposalCount'], $notifications['proposalEventCount']) = $this->_getProposalCount($user, $mode);
|
||||
$notifications['total'] = $notifications['proposalCount'];
|
||||
if (Configure::read('MISP.delegation')) {
|
||||
$notifications['delegationCount'] = $this->_getDelegationCount($user);
|
||||
$notifications['total'] += $notifications['delegationCount'];
|
||||
}
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
// if not using $mode === 'full', simply check if an entry exists. We really don't care about the real count for the top menu.
|
||||
private function _getProposalCount($user, $mode = 'full')
|
||||
{
|
||||
$this->ShadowAttribute = ClassRegistry::init('ShadowAttribute');
|
||||
$results[0] = $this->ShadowAttribute->find(
|
||||
'count',
|
||||
array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.event_org_id' => $user['org_id'],
|
||||
'ShadowAttribute.deleted' => 0,
|
||||
)
|
||||
)
|
||||
);
|
||||
if ($mode === 'full') {
|
||||
$results[1] = $this->ShadowAttribute->find(
|
||||
'count',
|
||||
array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.event_org_id' => $user['org_id'],
|
||||
'ShadowAttribute.deleted' => 0,
|
||||
),
|
||||
'fields' => 'distinct event_id'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$results[1] = $results[0];
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function _getDelegationCount($user)
|
||||
{
|
||||
$this->EventDelegation = ClassRegistry::init('EventDelegation');
|
||||
$delegations = $this->EventDelegation->find('count', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('EventDelegation.org_id' => $user['org_id'])
|
||||
));
|
||||
return $delegations;
|
||||
}
|
||||
|
||||
public function checkFilename($filename)
|
||||
{
|
||||
return preg_match('@^([a-z0-9_.]+[a-z0-9_.\- ]*[a-z0-9_.\-]|[a-z0-9_.])+$@i', $filename);
|
||||
|
@ -3211,6 +3172,7 @@ class AppModel extends Model
|
|||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'callbacks' => false,
|
||||
'order' => [], // disable order
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
@ -794,7 +794,6 @@ class Attribute extends AppModel
|
|||
|
||||
public function runValidation($value, $type)
|
||||
{
|
||||
$returnValue = false;
|
||||
// check data validation
|
||||
switch ($type) {
|
||||
case 'md5':
|
||||
|
@ -822,24 +821,19 @@ class Attribute extends AppModel
|
|||
case 'git-commit-id':
|
||||
if ($this->isHashValid($type, $value)) {
|
||||
return true;
|
||||
} else {
|
||||
$length = self::HEX_HAS_LENGTHS[$type];
|
||||
return __('Checksum has an invalid length or format (expected: %s hexadecimal characters). Please double check the value or select type "other".', $length);
|
||||
}
|
||||
$length = self::HEX_HAS_LENGTHS[$type];
|
||||
return __('Checksum has an invalid length or format (expected: %s hexadecimal characters). Please double check the value or select type "other".', $length);
|
||||
case 'tlsh':
|
||||
if (preg_match("#^[0-9a-f]{35,}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Checksum has an invalid length or format (expected: at least 35 hexadecimal characters). Please double check the value or select type "other".');
|
||||
if (preg_match("#^t?[0-9a-f]{35,}$#i", $value)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Checksum has an invalid length or format (expected: at least 35 hexadecimal characters, optionally starting with t1 instead of hexadecimal characters). Please double check the value or select type "other".');
|
||||
case 'pehash':
|
||||
if ($this->isHashValid('pehash', $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('The input doesn\'t match the expected sha1 format (expected: 40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('The input doesn\'t match the expected sha1 format (expected: 40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!');
|
||||
case 'ssdeep':
|
||||
if (substr_count($value, ':') === 2) {
|
||||
$parts = explode(':', $value);
|
||||
|
@ -852,35 +846,26 @@ class Attribute extends AppModel
|
|||
if (substr_count($value, ':') === 2) {
|
||||
$parts = explode(':', $value);
|
||||
if ($this->isPositiveInteger($parts[0])) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!$returnValue) {
|
||||
$returnValue = __('Invalid impfuzzy format. The format has to be imports:hash:hash');
|
||||
}
|
||||
break;
|
||||
return __('Invalid impfuzzy format. The format has to be imports:hash:hash');
|
||||
case 'cdhash':
|
||||
if (preg_match("#^[0-9a-f]{40,}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('The input doesn\'t match the expected format (expected: 40 or more hexadecimal characters)');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('The input doesn\'t match the expected format (expected: 40 or more hexadecimal characters)');
|
||||
case 'http-method':
|
||||
if (preg_match("#(OPTIONS|GET|HEAD|POST|PUT|DELETE|TRACE|CONNECT|PROPFIND|PROPPATCH|MKCOL|COPY|MOVE|LOCK|UNLOCK|VERSION-CONTROL|REPORT|CHECKOUT|CHECKIN|UNCHECKOUT|MKWORKSPACE|UPDATE|LABEL|MERGE|BASELINE-CONTROL|MKACTIVITY|ORDERPATCH|ACL|PATCH|SEARCH)#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Unknown HTTP method.');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Unknown HTTP method.');
|
||||
case 'filename|pehash':
|
||||
// no newline
|
||||
if (preg_match("#^.+\|[0-9a-f]{40}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('The input doesn\'t match the expected filename|sha1 format (expected: filename|40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('The input doesn\'t match the expected filename|sha1 format (expected: filename|40 hexadecimal characters). Keep in mind that MISP currently only supports SHA1 for PEhashes, if you would like to get the support extended to other hash types, make sure to create a github ticket about it at https://github.com/MISP/MISP!');
|
||||
case 'filename|md5':
|
||||
case 'filename|sha1':
|
||||
case 'filename|imphash':
|
||||
|
@ -898,42 +883,33 @@ class Attribute extends AppModel
|
|||
$parts = explode('|', $type);
|
||||
$length = self::HEX_HAS_LENGTHS[$parts[1]];
|
||||
if (preg_match("#^.+\|[0-9a-f]{" . $length . "}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Checksum has an invalid length or format (expected: filename|%s hexadecimal characters). Please double check the value or select type "other".', $length);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Checksum has an invalid length or format (expected: filename|%s hexadecimal characters). Please double check the value or select type "other".', $length);
|
||||
case 'filename|ssdeep':
|
||||
if (substr_count($value, '|') != 1 || !preg_match("#^.+\|.+$#", $value)) {
|
||||
$returnValue = __('Invalid composite type. The format has to be %s.', $type);
|
||||
return __('Invalid composite type. The format has to be %s.', $type);
|
||||
} else {
|
||||
$composite = explode('|', $value);
|
||||
$value = $composite[1];
|
||||
if (substr_count($value, ':') == 2) {
|
||||
$parts = explode(':', $value);
|
||||
if ($this->isPositiveInteger($parts[0])) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!$returnValue) {
|
||||
$returnValue = __('Invalid SSDeep hash (expected: blocksize:hash:hash).');
|
||||
}
|
||||
}
|
||||
break;
|
||||
return __('Invalid SSDeep hash (expected: blocksize:hash:hash).');
|
||||
case 'filename|tlsh':
|
||||
if (preg_match("#^.+\|[0-9a-f]{35,}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Checksum has an invalid length or format (expected: filename|at least 35 hexadecimal characters). Please double check the value or select type "other".');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Checksum has an invalid length or format (expected: filename|at least 35 hexadecimal characters). Please double check the value or select type "other".');
|
||||
case 'filename|vhash':
|
||||
if (preg_match('#^.+\|.+$#', $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Checksum has an invalid length or format (expected: filename|string characters). Please double check the value or select type "other".');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Checksum has an invalid length or format (expected: filename|string characters). Please double check the value or select type "other".');
|
||||
case 'ip-src':
|
||||
case 'ip-dst':
|
||||
if (strpos($value, '/') !== false) {
|
||||
|
@ -957,14 +933,11 @@ class Attribute extends AppModel
|
|||
return __('IP address has an invalid format.');
|
||||
}
|
||||
return true;
|
||||
|
||||
case 'port':
|
||||
if (!$this->isPortValid($value)) {
|
||||
$returnValue = __('Port numbers have to be integers between 1 and 65535.');
|
||||
} else {
|
||||
$returnValue = true;
|
||||
return __('Port numbers have to be integers between 1 and 65535.');
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case 'ip-dst|port':
|
||||
case 'ip-src|port':
|
||||
$parts = explode('|', $value);
|
||||
|
@ -977,22 +950,20 @@ class Attribute extends AppModel
|
|||
return true;
|
||||
case 'mac-address':
|
||||
if (preg_match('/^([a-fA-F0-9]{2}[:]?){6}$/', $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'mac-eui-64':
|
||||
if (preg_match('/^([a-fA-F0-9]{2}[:]?){8}$/', $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'hostname':
|
||||
case 'domain':
|
||||
if ($this->isDomainValid($value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('%s has an invalid format. Please double check the value or select type "other".', ucfirst($type));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('%s has an invalid format. Please double check the value or select type "other".', ucfirst($type));
|
||||
case 'hostname|port':
|
||||
$parts = explode('|', $value);
|
||||
if (!$this->isDomainValid($parts[0])) {
|
||||
|
@ -1006,14 +977,12 @@ class Attribute extends AppModel
|
|||
if (preg_match("#^[A-Z0-9.\-_]+\.[A-Z0-9\-]{2,}\|.*$#i", $value)) {
|
||||
$parts = explode('|', $value);
|
||||
if (filter_var($parts[1], FILTER_VALIDATE_IP)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
} else {
|
||||
$returnValue = __('IP address has an invalid format.');
|
||||
return __('IP address has an invalid format.');
|
||||
}
|
||||
} else {
|
||||
$returnValue = __('Domain name has an invalid format.');
|
||||
}
|
||||
break;
|
||||
return __('Domain name has an invalid format.');
|
||||
case 'email':
|
||||
case 'email-src':
|
||||
case 'eppn':
|
||||
|
@ -1024,38 +993,30 @@ class Attribute extends AppModel
|
|||
case 'jabber-id':
|
||||
// we don't use the native function to prevent issues with partial email addresses
|
||||
if (preg_match("#^.*\@.*\..*$#i", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Email address has an invalid format. Please double check the value or select type "other".');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Email address has an invalid format. Please double check the value or select type "other".');
|
||||
case 'vulnerability':
|
||||
if (preg_match("#^(CVE-)[0-9]{4}(-)[0-9]{4,}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Invalid format. Expected: CVE-xxxx-xxxx...');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Invalid format. Expected: CVE-xxxx-xxxx...');
|
||||
case 'weakness':
|
||||
if (preg_match("#^(CWE-)[0-9]{1,}$#", $value)) {
|
||||
$returnValue = true;
|
||||
} else {
|
||||
$returnValue = __('Invalid format. Expected: CWE-x...');
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Invalid format. Expected: CWE-x...');
|
||||
case 'named pipe':
|
||||
if (!preg_match("#\n#", $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'windows-service-name':
|
||||
case 'windows-service-displayname':
|
||||
if (strlen($value) > 256 || preg_match('#[\\\/]#', $value)) {
|
||||
$returnValue = __('Invalid format. Only values shorter than 256 characters that don\'t include any forward or backward slashes are allowed.');
|
||||
} else {
|
||||
$returnValue = true;
|
||||
return __('Invalid format. Only values shorter than 256 characters that don\'t include any forward or backward slashes are allowed.');
|
||||
}
|
||||
break;
|
||||
return true;
|
||||
case 'mutex':
|
||||
case 'process-state':
|
||||
case 'snort':
|
||||
|
@ -1090,12 +1051,11 @@ class Attribute extends AppModel
|
|||
case 'middle-name':
|
||||
case 'last-name':
|
||||
case 'full-name':
|
||||
$returnValue = true;
|
||||
break;
|
||||
return true;
|
||||
case 'link':
|
||||
// Moved to a native function whilst still enforcing the scheme as a requirement
|
||||
if (filter_var($value, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED) && !preg_match("#\n#", $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'hex':
|
||||
|
@ -1164,38 +1124,33 @@ class Attribute extends AppModel
|
|||
}
|
||||
return true;
|
||||
case 'datetime':
|
||||
try {
|
||||
new DateTime($value);
|
||||
$returnValue = true;
|
||||
} catch (Exception $e) {
|
||||
$returnValue = __('Datetime has to be in the ISO 8601 format.');
|
||||
if (strtotime($value) !== false) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
return __('Datetime has to be in the ISO 8601 format.');
|
||||
case 'size-in-bytes':
|
||||
case 'counter':
|
||||
if ($this->isPositiveInteger($value)) {
|
||||
return true;
|
||||
}
|
||||
return __('The value has to be a whole number greater or equal 0.');
|
||||
case 'targeted-threat-index':
|
||||
/* case 'targeted-threat-index':
|
||||
if (!is_numeric($value) || $value < 0 || $value > 10) {
|
||||
$returnValue = __('The value has to be a number between 0 and 10.');
|
||||
} else {
|
||||
$returnValue = true;
|
||||
return __('The value has to be a number between 0 and 10.');
|
||||
}
|
||||
break;
|
||||
return true;*/
|
||||
case 'iban':
|
||||
case 'bic':
|
||||
case 'btc':
|
||||
case 'dash':
|
||||
case 'xmr':
|
||||
if (preg_match('/^[a-zA-Z0-9]+$/', $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'vhash':
|
||||
if (preg_match('/^.+$/', $value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'bin':
|
||||
|
@ -1206,18 +1161,17 @@ class Attribute extends AppModel
|
|||
case 'phone-number':
|
||||
case 'whois-registrant-phone':
|
||||
if (is_numeric($value)) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'cortex':
|
||||
json_decode($value);
|
||||
$returnValue = (json_last_error() == JSON_ERROR_NONE);
|
||||
break;
|
||||
return json_last_error() === JSON_ERROR_NONE;
|
||||
case 'float':
|
||||
return is_numeric($value);
|
||||
case 'boolean':
|
||||
if ($value == 1 || $value == 0) {
|
||||
$returnValue = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'AS':
|
||||
|
@ -1226,7 +1180,7 @@ class Attribute extends AppModel
|
|||
}
|
||||
return __('AS number have to be integers between 1 and 4294967295');
|
||||
}
|
||||
return $returnValue;
|
||||
return false;
|
||||
}
|
||||
|
||||
// do some last second modifications before the validation
|
||||
|
|
|
@ -539,23 +539,23 @@ class Event extends AppModel
|
|||
{
|
||||
$tagsToFetch = array();
|
||||
foreach ($events as $event) {
|
||||
if (!empty($event['EventTag'])) {
|
||||
foreach ($event['EventTag'] as $et) {
|
||||
$tagsToFetch[$et['tag_id']] = $et['tag_id'];
|
||||
}
|
||||
foreach ($event['EventTag'] as $et) {
|
||||
$tagsToFetch[$et['tag_id']] = $et['tag_id'];
|
||||
}
|
||||
}
|
||||
if (empty($tagsToFetch)) {
|
||||
return $events;
|
||||
}
|
||||
$tags = $this->EventTag->Tag->find('all', array(
|
||||
'conditions' => array('Tag.id' => $tagsToFetch),
|
||||
'recursive' => -1,
|
||||
'fields' => ['id', 'name', 'colour', 'is_galaxy'], // fetch just necessary columns
|
||||
'order' => false
|
||||
));
|
||||
$tags = array_column(array_column($tags, 'Tag'), null, 'id');
|
||||
foreach ($events as &$event) {
|
||||
if (!empty($event['EventTag'])) {
|
||||
foreach ($event['EventTag'] as &$et) {
|
||||
$et['Tag'] = $tags[$et['tag_id']];
|
||||
}
|
||||
foreach ($event['EventTag'] as &$et) {
|
||||
$et['Tag'] = $tags[$et['tag_id']];
|
||||
}
|
||||
}
|
||||
return $events;
|
||||
|
@ -1960,7 +1960,7 @@ class Event extends AppModel
|
|||
$conditions['AND'][] = array('Event.published' => 1);
|
||||
$conditionsAttributes['AND'][] = array('Attribute.to_ids' => 1);
|
||||
}
|
||||
$softDeletables = array('Attribute', 'Object', 'ObjectReference', 'EventReport');
|
||||
$softDeletables = array('Attribute', 'Object', 'EventReport');
|
||||
if (isset($options['deleted'])) {
|
||||
if (!is_array($options['deleted'])) {
|
||||
$options['deleted'] = array($options['deleted']);
|
||||
|
@ -2040,7 +2040,6 @@ class Event extends AppModel
|
|||
$fieldsAtt = array('Attribute.id', 'Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.to_ids', 'Attribute.uuid', 'Attribute.event_id', 'Attribute.distribution', 'Attribute.timestamp', 'Attribute.comment', 'Attribute.sharing_group_id', 'Attribute.deleted', 'Attribute.disable_correlation', 'Attribute.object_id', 'Attribute.object_relation', 'Attribute.first_seen', 'Attribute.last_seen');
|
||||
$fieldsShadowAtt = array('ShadowAttribute.id', 'ShadowAttribute.type', 'ShadowAttribute.category', 'ShadowAttribute.value', 'ShadowAttribute.to_ids', 'ShadowAttribute.uuid', 'ShadowAttribute.event_uuid', 'ShadowAttribute.event_id', 'ShadowAttribute.old_id', 'ShadowAttribute.comment', 'ShadowAttribute.org_id', 'ShadowAttribute.proposal_to_delete', 'ShadowAttribute.timestamp', 'ShadowAttribute.first_seen', 'ShadowAttribute.last_seen');
|
||||
$fieldsOrg = array('id', 'name', 'uuid', 'local');
|
||||
$fieldsEventReport = array('*');
|
||||
$params = array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => 0,
|
||||
|
@ -2052,17 +2051,11 @@ class Event extends AppModel
|
|||
'Attribute' => array(
|
||||
'fields' => $fieldsAtt,
|
||||
'conditions' => $conditionsAttributes,
|
||||
'AttributeTag' => array(
|
||||
'order' => false
|
||||
),
|
||||
'order' => false
|
||||
),
|
||||
'Object' => array(
|
||||
'conditions' => $conditionsObjects,
|
||||
'order' => false,
|
||||
'ObjectReference' => array(
|
||||
'order' => false
|
||||
)
|
||||
),
|
||||
'ShadowAttribute' => array(
|
||||
'fields' => $fieldsShadowAtt,
|
||||
|
@ -2074,7 +2067,6 @@ class Event extends AppModel
|
|||
'order' => false
|
||||
),
|
||||
'EventReport' => array(
|
||||
'fields' => $fieldsEventReport,
|
||||
'conditions' => $conditionsEventReport,
|
||||
'order' => false
|
||||
)
|
||||
|
@ -2084,9 +2076,6 @@ class Event extends AppModel
|
|||
$params['contain']['EventTag']['conditions'] = array(
|
||||
'EventTag.local' => 0
|
||||
);
|
||||
$params['contain']['Attribute']['AttributeTag']['conditions'] = array(
|
||||
'AttributeTag.local' => 0
|
||||
);
|
||||
}
|
||||
if ($flatten) {
|
||||
unset($params['contain']['Object']);
|
||||
|
@ -2124,6 +2113,9 @@ class Event extends AppModel
|
|||
if (!empty($options['includeDecayScore']) && !isset($this->DecayingModel)) {
|
||||
$this->DecayingModel = ClassRegistry::init('DecayingModel');
|
||||
}
|
||||
if ($options['includeServerCorrelations'] && !$isSiteAdmin && $user['org_id'] != Configure::read('MISP.host_org_id')) {
|
||||
$options['includeServerCorrelations'] = false; // not permission to see server correlations
|
||||
}
|
||||
if (($options['includeFeedCorrelations'] || $options['includeServerCorrelations']) && !isset($this->Feed)) {
|
||||
$this->Feed = ClassRegistry::init('Feed');
|
||||
}
|
||||
|
@ -2139,6 +2131,20 @@ class Event extends AppModel
|
|||
$justExportableTags = false;
|
||||
}
|
||||
|
||||
$overrideLimit = !empty($options['overrideLimit']);
|
||||
|
||||
if (!empty($options['allow_proposal_blocking']) && !Configure::read('MISP.proposals_block_attributes')) {
|
||||
$options['allow_proposal_blocking'] = false; // proposal blocking is not enabled
|
||||
}
|
||||
|
||||
if (!$options['metadata']) {
|
||||
$this->__attachAttributeTags($results, $options['excludeLocalTags']);
|
||||
}
|
||||
|
||||
if (!$options['metadata'] && !$flatten) {
|
||||
$this->__attachReferences($results);
|
||||
}
|
||||
|
||||
foreach ($results as &$event) {
|
||||
/*
|
||||
// REMOVING THIS FOR NOW - users should see data they own, even if they're not in the sharing group.
|
||||
|
@ -2164,7 +2170,6 @@ class Event extends AppModel
|
|||
$this->Warninglist->attachWarninglistToAttributes($event['ShadowAttribute']);
|
||||
$event['warnings'] = $eventWarnings;
|
||||
}
|
||||
$this->__attachReferences($event);
|
||||
$this->__attachTags($event, $justExportableTags);
|
||||
$this->__attachGalaxies($event, $user, $options['excludeGalaxy'], $options['fetchFullClusters']);
|
||||
$event = $this->Orgc->attachOrgs($event, $fieldsOrg);
|
||||
|
@ -2202,29 +2207,36 @@ class Event extends AppModel
|
|||
}
|
||||
$event['RelatedShadowAttribute'] = $this->getRelatedAttributes($user, $event['Event']['id'], true);
|
||||
}
|
||||
if (!empty($event['ShadowAttribute']) && $options['includeAttachments']) {
|
||||
foreach ($event['ShadowAttribute'] as $k => $sa) {
|
||||
if ($this->ShadowAttribute->typeIsAttachment($sa['type'])) {
|
||||
$encodedFile = $this->ShadowAttribute->base64EncodeAttachment($sa);
|
||||
$event['ShadowAttribute'][$k]['data'] = $encodedFile;
|
||||
}
|
||||
$shadowAttributeByOldId = [];
|
||||
if (!empty($event['ShadowAttribute'])) {
|
||||
if ($isSiteAdmin && $options['includeFeedCorrelations']) {
|
||||
$event['ShadowAttribute'] = $this->Feed->attachFeedCorrelations($event['ShadowAttribute'], $user, $event['Event'], $overrideLimit);
|
||||
}
|
||||
if ($options['includeServerCorrelations']) {
|
||||
$event['ShadowAttribute'] = $this->Feed->attachFeedCorrelations($event['ShadowAttribute'], $user, $event['Event'], $overrideLimit, 'Server');
|
||||
}
|
||||
|
||||
if ($options['includeAttachments']) {
|
||||
foreach ($event['ShadowAttribute'] as &$sa) {
|
||||
if ($this->ShadowAttribute->typeIsAttachment($sa['type'])) {
|
||||
$encodedFile = $this->ShadowAttribute->base64EncodeAttachment($sa);
|
||||
$sa['data'] = $encodedFile;
|
||||
}
|
||||
}
|
||||
unset($sa);
|
||||
}
|
||||
|
||||
foreach ($event['ShadowAttribute'] as $sa) {
|
||||
$shadowAttributeByOldId[$sa['old_id']][] = $sa;
|
||||
}
|
||||
// Assign just shadow attributes that are linked to event (that means they have old_id set to `0`)
|
||||
$event['ShadowAttribute'] = $shadowAttributeByOldId[0] ?? [];
|
||||
}
|
||||
if (!empty($event['Attribute'])) {
|
||||
if ($options['includeFeedCorrelations']) {
|
||||
if (!empty($options['overrideLimit'])) {
|
||||
$overrideLimit = true;
|
||||
} else {
|
||||
$overrideLimit = false;
|
||||
}
|
||||
$event['Attribute'] = $this->Feed->attachFeedCorrelations($event['Attribute'], $user, $event['Event'], $overrideLimit);
|
||||
}
|
||||
if (!empty($options['includeServerCorrelations']) && ($user['Role']['perm_site_admin'] || $user['org_id'] == Configure::read('MISP.host_org_id'))) {
|
||||
if (!empty($options['overrideLimit'])) {
|
||||
$overrideLimit = true;
|
||||
} else {
|
||||
$overrideLimit = false;
|
||||
}
|
||||
if ($options['includeServerCorrelations']) {
|
||||
$event['Attribute'] = $this->Feed->attachFeedCorrelations($event['Attribute'], $user, $event['Event'], $overrideLimit, 'Server');
|
||||
}
|
||||
$event = $this->__filterBlockedAttributesByTags($event, $options, $user);
|
||||
|
@ -2232,54 +2244,42 @@ class Event extends AppModel
|
|||
$event['Attribute'] = $this->__attachSharingGroups($event['Attribute'], $sharingGroupData);
|
||||
}
|
||||
|
||||
$proposalBlockAttributes = Configure::read('MISP.proposals_block_attributes');
|
||||
// move all object attributes to a temporary container
|
||||
$tempObjectAttributeContainer = array();
|
||||
foreach ($event['Attribute'] as $key => $attribute) {
|
||||
foreach ($event['Attribute'] as $key => &$attribute) {
|
||||
if ($options['enforceWarninglist'] && !empty($attribute['warnings'])) {
|
||||
unset($event['Attribute'][$key]);
|
||||
continue;
|
||||
}
|
||||
if ($attribute['category'] === 'Financial fraud') {
|
||||
$event['Attribute'][$key] = $this->Attribute->attachValidationWarnings($event['Attribute'][$key]);
|
||||
$attribute = $this->Attribute->attachValidationWarnings($attribute);
|
||||
}
|
||||
if ($options['includeAttachments'] && $this->Attribute->typeIsAttachment($attribute['type'])) {
|
||||
$encodedFile = $this->Attribute->base64EncodeAttachment($attribute);
|
||||
$event['Attribute'][$key]['data'] = $encodedFile;
|
||||
$attribute['data'] = $encodedFile;
|
||||
}
|
||||
if (!empty($options['includeDecayScore'])) {
|
||||
if (isset($event['EventTag'])) { // include EventTags for score computation
|
||||
$event['Attribute'][$key]['EventTag'] = $event['EventTag'];
|
||||
$attribute['EventTag'] = $event['EventTag'];
|
||||
}
|
||||
$event['Attribute'][$key] = $this->DecayingModel->attachScoresToAttribute($user, $event['Attribute'][$key]);
|
||||
$attribute = $this->DecayingModel->attachScoresToAttribute($user, $attribute);
|
||||
if (isset($event['EventTag'])) { // remove included EventTags
|
||||
unset($event['Attribute'][$key]['EventTag']);
|
||||
unset($attribute['EventTag']);
|
||||
}
|
||||
}
|
||||
$event['Attribute'][$key]['ShadowAttribute'] = array();
|
||||
// If a shadowattribute can be linked to an attribute, link it to it then remove it from the event
|
||||
// If a shadowattribute can be linked to an attribute, link it to it
|
||||
// This is to differentiate between proposals that were made to an attribute for modification and between proposals for new attributes
|
||||
|
||||
if (isset($event['ShadowAttribute'])) {
|
||||
foreach ($event['ShadowAttribute'] as $k => $sa) {
|
||||
if (!empty($sa['old_id'])) {
|
||||
if ($event['ShadowAttribute'][$k]['old_id'] == $attribute['id']) {
|
||||
$event['Attribute'][$key]['ShadowAttribute'][] = $sa;
|
||||
unset($event['ShadowAttribute'][$k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($proposalBlockAttributes && !empty($options['allow_proposal_blocking'])) {
|
||||
foreach ($event['Attribute'][$key]['ShadowAttribute'] as $sa) {
|
||||
$attribute['ShadowAttribute'] = $shadowAttributeByOldId[$attribute['id']] ?? [];
|
||||
if (!empty($options['allow_proposal_blocking'])) {
|
||||
foreach ($attribute['ShadowAttribute'] as $sa) {
|
||||
if ($sa['proposal_to_delete'] || $sa['to_ids'] == 0) {
|
||||
unset($event['Attribute'][$key]);
|
||||
continue;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$flatten && $attribute['object_id'] != 0) {
|
||||
$tempObjectAttributeContainer[$attribute['object_id']][] = $event['Attribute'][$key];
|
||||
$tempObjectAttributeContainer[$attribute['object_id']][] = $attribute;
|
||||
unset($event['Attribute'][$key]);
|
||||
}
|
||||
}
|
||||
|
@ -2289,9 +2289,9 @@ class Event extends AppModel
|
|||
if (!$sharingGroupReferenceOnly) {
|
||||
$event['Object'] = $this->__attachSharingGroups($event['Object'], $sharingGroupData);
|
||||
}
|
||||
foreach ($event['Object'] as $objectKey => $objectValue) {
|
||||
foreach ($event['Object'] as &$objectValue) {
|
||||
if (isset($tempObjectAttributeContainer[$objectValue['id']])) {
|
||||
$event['Object'][$objectKey]['Attribute'] = $tempObjectAttributeContainer[$objectValue['id']];
|
||||
$objectValue['Attribute'] = $tempObjectAttributeContainer[$objectValue['id']];
|
||||
}
|
||||
}
|
||||
unset($tempObjectAttributeContainer);
|
||||
|
@ -2299,33 +2299,6 @@ class Event extends AppModel
|
|||
if (!$sharingGroupReferenceOnly && !empty($event['EventReport'])) {
|
||||
$event['EventReport'] = $this->__attachSharingGroups($event['EventReport'], $sharingGroupData);
|
||||
}
|
||||
if (!empty($event['ShadowAttribute'])) {
|
||||
if ($isSiteAdmin && $options['includeFeedCorrelations']) {
|
||||
if (!empty($options['overrideLimit'])) {
|
||||
$overrideLimit = true;
|
||||
} else {
|
||||
$overrideLimit = false;
|
||||
}
|
||||
$event['ShadowAttribute'] = $this->Feed->attachFeedCorrelations($event['ShadowAttribute'], $user, $event['Event'], $overrideLimit);
|
||||
}
|
||||
if (!empty($options['includeServerCorrelations']) && $user['org_id'] == Configure::read('MISP.host_org_id')) {
|
||||
if (!empty($options['overrideLimit'])) {
|
||||
$overrideLimit = true;
|
||||
} else {
|
||||
$overrideLimit = false;
|
||||
}
|
||||
$event['ShadowAttribute'] = $this->Feed->attachFeedCorrelations($event['ShadowAttribute'], $user, $event['Event'], $overrideLimit, 'Server');
|
||||
}
|
||||
|
||||
// remove proposals to attributes that we cannot see
|
||||
// if the shadow attribute wasn't moved within an attribute before, this is the case
|
||||
foreach ($event['ShadowAttribute'] as $k => $sa) {
|
||||
if (!empty($sa['old_id'])) {
|
||||
unset($event['ShadowAttribute'][$k]);
|
||||
}
|
||||
}
|
||||
$event['ShadowAttribute'] = array_values($event['ShadowAttribute']);
|
||||
}
|
||||
if (empty($options['metadata']) && empty($options['noSightings'])) {
|
||||
$event['Sighting'] = $this->Sighting->attachToEvent($event, $user);
|
||||
}
|
||||
|
@ -3880,9 +3853,12 @@ class Event extends AppModel
|
|||
foreach ($referencesToCapture as $referenceToCapture) {
|
||||
$result = $this->Object->ObjectReference->captureReference(
|
||||
$referenceToCapture,
|
||||
$this->id,
|
||||
$user
|
||||
$this->id
|
||||
);
|
||||
if ($result !== true) {
|
||||
$title = "Could not save object reference when capturing event with ID {$this->id}";
|
||||
$this->loadLog()->validationError($user, 'add', 'ObjectReference', $title, $result, $referenceToCapture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4099,7 +4075,11 @@ class Event extends AppModel
|
|||
foreach ($object['ObjectReference'] as $objectRef) {
|
||||
$nothingToChange = false;
|
||||
$objectRef['source_uuid'] = $object['uuid'];
|
||||
$result = $this->Object->ObjectReference->captureReference($objectRef, $this->id, $user);
|
||||
$result = $this->Object->ObjectReference->captureReference($objectRef, $this->id);
|
||||
if ($result !== true) {
|
||||
$title = "Could not save object reference when capturing event with ID {$this->id}";
|
||||
$this->loadLog()->validationError($user, 'edit', 'ObjectReference', $title, $result, $objectRef);
|
||||
}
|
||||
if ($result && !$nothingToChange) {
|
||||
$changed = true;
|
||||
}
|
||||
|
@ -6841,6 +6821,123 @@ class Event extends AppModel
|
|||
return $this->processModuleResultsData($user, $resolved_data, $id, $default_comment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach references to objects faster than CakePHP.
|
||||
* @param array $events
|
||||
*/
|
||||
private function __attachReferences(array &$events)
|
||||
{
|
||||
$eventIds = [];
|
||||
foreach ($events as $event) {
|
||||
if (!empty($event['Object'])) {
|
||||
$eventIds[] = $event['Event']['id']; // event contains objects
|
||||
}
|
||||
}
|
||||
if (!empty($eventIds)) {
|
||||
// Do not fetch fields that we already know to reduce memory usage
|
||||
$schema = $this->Object->ObjectReference->schema();
|
||||
unset($schema['event_id']);
|
||||
unset($schema['source_uuid']);
|
||||
|
||||
$references = $this->Object->ObjectReference->find('all', [
|
||||
'conditions' => ['ObjectReference.event_id' => $eventIds],
|
||||
'fields' => array_keys($schema),
|
||||
'recursive' => -1,
|
||||
]);
|
||||
}
|
||||
if (empty($references)) {
|
||||
// Assign empty object reference object
|
||||
foreach ($events as &$event) {
|
||||
foreach ($event['Object'] as &$object) {
|
||||
$object['ObjectReference'] = [];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
$referencesForObject = [];
|
||||
foreach ($references as $reference) {
|
||||
$referencesForObject[$reference['ObjectReference']['object_id']][] = $reference['ObjectReference'];
|
||||
}
|
||||
$fieldsToCopy = array(
|
||||
'common' => array('distribution', 'sharing_group_id', 'uuid'),
|
||||
'Attribute' => array('value', 'type', 'category', 'to_ids'),
|
||||
'Object' => array('name', 'meta-category')
|
||||
);
|
||||
foreach ($events as &$event) {
|
||||
$eventIdCache = [];
|
||||
foreach ($event['Object'] as &$object) {
|
||||
$objectReferences = $referencesForObject[$object['id']] ?? [];
|
||||
foreach ($objectReferences as &$reference) {
|
||||
$reference['event_id'] = $event['Event']['id'];
|
||||
$reference['source_uuid'] = $object['uuid'];
|
||||
// find referenced object in current event
|
||||
$type = $reference['referenced_type'] == 0 ? 'Attribute' : 'Object';
|
||||
// construct array with ID in key, so we can search attributes and objects by ID faster
|
||||
if (!isset($eventIdCache[$type])) {
|
||||
$eventIdCache[$type] = array_column($event[$type], null, 'id');
|
||||
}
|
||||
$found = $eventIdCache[$type][$reference['referenced_id']] ?? null;
|
||||
|
||||
if ($found) {
|
||||
// copy requested fields
|
||||
$copied = [];
|
||||
foreach (array_merge($fieldsToCopy['common'], $fieldsToCopy[$type]) as $field) {
|
||||
$copied[$field] = $found[$field];
|
||||
}
|
||||
$reference[$type] = $copied;
|
||||
} else { // object / attribute might be from an extended event
|
||||
$otherEventText = __('%s from another event', $type);
|
||||
$reference[$type] = [
|
||||
'name' => '',
|
||||
'meta-category' => $otherEventText,
|
||||
'category' => $otherEventText,
|
||||
'type' => '',
|
||||
'value' => '',
|
||||
'uuid' => $reference['referenced_uuid']
|
||||
];
|
||||
}
|
||||
}
|
||||
$object['ObjectReference'] = $objectReferences;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Faster way how to attach tags to events that integrated in CakePHP.
|
||||
* @param array $events
|
||||
* @param bool $excludeLocalTags
|
||||
*/
|
||||
private function __attachAttributeTags(array &$events, $excludeLocalTags = false)
|
||||
{
|
||||
$eventIds = array_column(array_column($events, 'Event'), 'id');
|
||||
$conditions = ['AttributeTag.event_id' => $eventIds];
|
||||
if ($excludeLocalTags) {
|
||||
$conditions['AttributeTag.local'] = false;
|
||||
}
|
||||
$ats = $this->Attribute->AttributeTag->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'fields' => ['AttributeTag.attribute_id', 'AttributeTag.tag_id', 'AttributeTag.local'], // we don't need id or event_id
|
||||
'recursive' => -1,
|
||||
]);
|
||||
if (empty($ats)) {
|
||||
foreach ($events as &$event) {
|
||||
foreach ($event['Attribute'] as &$attribute) {
|
||||
$attribute['AttributeTag'] = [];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
$atForAttributes = [];
|
||||
foreach ($ats as $at) {
|
||||
$atForAttributes[$at['AttributeTag']['attribute_id']][] = $at['AttributeTag'];
|
||||
}
|
||||
foreach ($events as &$event) {
|
||||
foreach ($event['Attribute'] as &$attribute) {
|
||||
$attribute['AttributeTag'] = $atForAttributes[$attribute['id']] ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag from cache by given ID.
|
||||
*
|
||||
|
@ -6877,21 +6974,19 @@ class Event extends AppModel
|
|||
|
||||
if (!empty($event['Attribute'])) {
|
||||
foreach ($event['Attribute'] as $attribute) {
|
||||
if (!empty($attribute['AttributeTag'])) {
|
||||
foreach ($attribute['AttributeTag'] as $attributeTag) {
|
||||
$tagIds[$attributeTag['tag_id']] = true;
|
||||
}
|
||||
foreach ($attribute['AttributeTag'] as $attributeTag) {
|
||||
$tagIds[$attributeTag['tag_id']] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$notCachedTags = array_diff(array_keys($tagIds), isset($this->assetCache['tags']) ? array_keys($this->assetCache['tags']) : []);
|
||||
$notCachedTags = array_diff_key($tagIds, isset($this->assetCache['tags']) ? $this->assetCache['tags'] : []);
|
||||
if (empty($notCachedTags)) {
|
||||
return;
|
||||
}
|
||||
$conditions = ['id' => $notCachedTags];
|
||||
$conditions = ['Tag.id' => array_keys($notCachedTags)];
|
||||
if ($justExportable) {
|
||||
$conditions['exportable'] = 1;
|
||||
$conditions['Tag.exportable'] = 1;
|
||||
}
|
||||
$tags = $this->EventTag->Tag->find('all', [
|
||||
'recursive' => -1,
|
||||
|
@ -6942,58 +7037,6 @@ class Event extends AppModel
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach referenced object to ObjectReference. Since reference can be just to attribute or object in the same event,
|
||||
* we just find proper element in event.
|
||||
*
|
||||
* @param array $event
|
||||
*/
|
||||
private function __attachReferences(array &$event)
|
||||
{
|
||||
if (!isset($event['Object'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$fieldsToCopy = array(
|
||||
'common' => array('distribution', 'sharing_group_id', 'uuid'),
|
||||
'Attribute' => array('value', 'type', 'category', 'to_ids'),
|
||||
'Object' => array('name', 'meta-category')
|
||||
);
|
||||
|
||||
foreach ($event['Object'] as $k => $object) {
|
||||
foreach ($object['ObjectReference'] as $k2 => $reference) {
|
||||
// find referenced object in current event
|
||||
$type = $reference['referenced_type'] == 0 ? 'Attribute' : 'Object';
|
||||
$found = null;
|
||||
foreach ($event[$type] as $o) {
|
||||
if ($o['id'] == $reference['referenced_id']) {
|
||||
$found = $o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
// copy requested fields
|
||||
$reference = [];
|
||||
foreach (array_merge($fieldsToCopy['common'], $fieldsToCopy[$type]) as $field) {
|
||||
$reference[$field] = $found[$field];
|
||||
}
|
||||
$event['Object'][$k]['ObjectReference'][$k2][$type] = $reference;
|
||||
} else { // object / attribute might be from an extended event
|
||||
$otherEventText = __('%s from another event', $reference['referenced_type'] == 0 ? 'Attribute' : 'Object');
|
||||
$event['Object'][$k]['ObjectReference'][$k2][$type] = [
|
||||
'name' => '',
|
||||
'meta-category' => $otherEventText,
|
||||
'category' => $otherEventText,
|
||||
'type' => '',
|
||||
'value' => '',
|
||||
'uuid' => $reference['referenced_uuid']
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
* @param string $returnFormat
|
||||
|
@ -7350,7 +7393,7 @@ class Event extends AppModel
|
|||
public function addFiltersFromUserSettings($user, $filters)
|
||||
{
|
||||
$this->UserSetting = ClassRegistry::init('UserSetting');
|
||||
$defaultParameters = $this->UserSetting->getDefaulRestSearchParameters($user);
|
||||
$defaultParameters = $this->UserSetting->getDefaultRestSearchParameters($user);
|
||||
$filters = array_replace_recursive($defaultParameters, $filters);
|
||||
return $filters;
|
||||
}
|
||||
|
|
|
@ -457,10 +457,6 @@ class GalaxyCluster extends AppModel
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
$this->Event = ClassRegistry::init('Event');
|
||||
$job_type = 'publish_cluster';
|
||||
$function = 'publish_galaxy_clusters';
|
||||
$message = 'Publishing.';
|
||||
$job = ClassRegistry::init('Job');
|
||||
$job->create();
|
||||
$data = array(
|
||||
|
@ -471,14 +467,14 @@ class GalaxyCluster extends AppModel
|
|||
'retries' => 0,
|
||||
'org_id' => $user['org_id'],
|
||||
'org' => $user['Organisation']['name'],
|
||||
'message' => $message
|
||||
'message' => 'Publishing.'
|
||||
);
|
||||
$job->save($data);
|
||||
$jobId = $job->id;
|
||||
$process_id = CakeResque::enqueue(
|
||||
'prio',
|
||||
'EventShell',
|
||||
array($function, $clusterId, $jobId, $user['id'], $passAlong),
|
||||
array('publish_galaxy_clusters', $clusterId, $jobId, $user['id'], $passAlong),
|
||||
true
|
||||
);
|
||||
$job->saveField('process_id', $process_id);
|
||||
|
|
|
@ -240,6 +240,9 @@ class Log extends AppModel
|
|||
if ($action === 'request' && !empty(Configure::read('MISP.log_paranoid_skip_db'))) {
|
||||
return null;
|
||||
}
|
||||
if (!empty(Configure::read('MISP.log_skip_db_logs_completely'))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new Exception("Cannot save log because of validation errors: " . json_encode($this->validationErrors));
|
||||
}
|
||||
|
@ -247,6 +250,22 @@ class Log extends AppModel
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $user
|
||||
* @param string $action
|
||||
* @param string $model
|
||||
* @param string $title
|
||||
* @param array $validationErrors
|
||||
* @param array $fullObject
|
||||
* @throws Exception
|
||||
*/
|
||||
public function validationError($user, $action, $model, $title, array $validationErrors, array $fullObject)
|
||||
{
|
||||
$this->log($title, LOG_WARNING);
|
||||
$change = 'Validation errors: ' . json_encode($validationErrors) . ' Full ' . $model . ': ' . json_encode($fullObject);
|
||||
$this->createLogEntry($user, $action, $model, 0, $title, $change);
|
||||
}
|
||||
|
||||
// to combat a certain bug that causes the upgrade scripts to loop without being able to set the correct version
|
||||
// this function remedies a fixed upgrade bug instance by eliminating the massive number of erroneous upgrade log entries
|
||||
public function pruneUpdateLogs($jobId = false, $user)
|
||||
|
|
|
@ -38,17 +38,38 @@ class ObjectReference extends AppModel
|
|||
)
|
||||
);
|
||||
|
||||
public $validate = [
|
||||
'uuid' => 'uuid',
|
||||
'object_id' => [
|
||||
'rule' => 'numeric',
|
||||
'required' => true,
|
||||
'on' => 'create',
|
||||
],
|
||||
'event_id' => [
|
||||
'rule' => 'numeric',
|
||||
'required' => true,
|
||||
'on' => 'create',
|
||||
],
|
||||
'source_uuid' => 'uuid',
|
||||
'referenced_uuid' => 'uuid',
|
||||
'referenced_id' => 'numeric',
|
||||
'referenced_type' => [
|
||||
'rule' => ['inList', ['0', '1']],
|
||||
],
|
||||
'deleted' => 'boolean',
|
||||
];
|
||||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
parent::beforeValidate();
|
||||
if (empty($this->data['ObjectReference']['uuid'])) {
|
||||
$this->data['ObjectReference']['uuid'] = CakeText::uuid();
|
||||
$reference = &$this->data['ObjectReference'];
|
||||
if (empty($reference['uuid'])) {
|
||||
$reference['uuid'] = CakeText::uuid();
|
||||
}
|
||||
if (empty($this->data['ObjectReference']['timestamp'])) {
|
||||
$this->data['ObjectReference']['timestamp'] = time();
|
||||
if (empty($reference['timestamp'])) {
|
||||
$reference['timestamp'] = time();
|
||||
}
|
||||
if (!isset($this->data['ObjectReference']['comment'])) {
|
||||
$this->data['ObjectReference']['comment'] = '';
|
||||
if (!isset($reference['comment'])) {
|
||||
$reference['comment'] = '';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -170,7 +191,13 @@ class ObjectReference extends AppModel
|
|||
return true;
|
||||
}
|
||||
|
||||
public function captureReference($reference, $eventId, $user)
|
||||
/**
|
||||
* @param array $reference
|
||||
* @param int $eventId
|
||||
* @return array|bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function captureReference(array $reference, $eventId)
|
||||
{
|
||||
if (isset($reference['uuid'])) {
|
||||
$existingReference = $this->find('first', array(
|
||||
|
@ -257,6 +284,9 @@ class ObjectReference extends AppModel
|
|||
$reference['object_uuid'] = $sourceObject['Object']['uuid'];
|
||||
$reference['event_id'] = $eventId;
|
||||
$result = $this->save(array('ObjectReference' => $reference));
|
||||
if (!$result) {
|
||||
return $this->validationErrors;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -308,7 +338,8 @@ class ObjectReference extends AppModel
|
|||
return array($referenced_id, $referenced_uuid, $referenced_type);
|
||||
}
|
||||
|
||||
function isValidExtendedEventForReference($sourceEvent, $targetEventID, $user) {
|
||||
private function isValidExtendedEventForReference(array $sourceEvent, $targetEventID, array $user)
|
||||
{
|
||||
if ($sourceEvent['Event']['orgc_id'] != $user['org_id']) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -3020,71 +3020,70 @@ class Server extends AppModel
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
private function compareDBIndexes(array $actualIndex, array $expectedIndex, array $dbExpectedSchema)
|
||||
{
|
||||
$allowedlistTables = array();
|
||||
$indexDiff = array();
|
||||
foreach ($expectedIndex as $tableName => $indexes) {
|
||||
if (!array_key_exists($tableName, $actualIndex)) {
|
||||
continue; // If table does not exists, it is covered by the schema diagnostic
|
||||
} elseif(in_array($tableName, $allowedlistTables)) {
|
||||
continue; // Ignore allowedlisted tables
|
||||
} else {
|
||||
$tableIndexDiff = array_diff(array_keys($indexes), array_keys($actualIndex[$tableName])); // check for missing indexes
|
||||
foreach ($tableIndexDiff as $columnDiff) {
|
||||
$shouldBeUnique = $indexes[$columnDiff];
|
||||
if ($shouldBeUnique && !$this->checkIfColumnContainsJustUniqueValues($tableName, $columnDiff)) {
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => __('Column `%s` should be unique indexed, but contains duplicate values', $columnDiff),
|
||||
'sql' => '',
|
||||
}
|
||||
$tableIndexDiff = array_diff(array_keys($indexes), array_keys($actualIndex[$tableName])); // check for missing indexes
|
||||
foreach ($tableIndexDiff as $columnDiff) {
|
||||
$shouldBeUnique = $indexes[$columnDiff];
|
||||
if ($shouldBeUnique && !$this->checkIfColumnContainsJustUniqueValues($tableName, $columnDiff)) {
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => __('Column `%s` should be unique indexed, but contains duplicate values', $columnDiff),
|
||||
'sql' => '',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$message = __('Column `%s` should be indexed', $columnDiff);
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => $message,
|
||||
'sql' => $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $columnDiff, $shouldBeUnique),
|
||||
);
|
||||
}
|
||||
$tableIndexDiff = array_diff(array_keys($actualIndex[$tableName]), array_keys($indexes)); // check for additional indexes
|
||||
foreach ($tableIndexDiff as $columnDiff) {
|
||||
$message = __('Column `%s` is indexed but should not', $columnDiff);
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => $message,
|
||||
'sql' => $this->generateSqlDropIndexQuery($tableName, $columnDiff),
|
||||
);
|
||||
}
|
||||
foreach ($indexes as $column => $unique) {
|
||||
if (isset($actualIndex[$tableName][$column]) && $actualIndex[$tableName][$column] != $unique) {
|
||||
if ($actualIndex[$tableName][$column]) {
|
||||
$sql = $this->generateSqlDropIndexQuery($tableName, $column);
|
||||
$sql .= '<br>' . $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $column, false);
|
||||
|
||||
$message = __('Column `%s` has unique index, but should be non unique', $column);
|
||||
$indexDiff[$tableName][$column] = array(
|
||||
'message' => $message,
|
||||
'sql' => $sql,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$message = __('Column `%s` should be indexed', $columnDiff);
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => $message,
|
||||
'sql' => $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $columnDiff, $shouldBeUnique),
|
||||
);
|
||||
}
|
||||
$tableIndexDiff = array_diff(array_keys($actualIndex[$tableName]), array_keys($indexes)); // check for additional indexes
|
||||
foreach ($tableIndexDiff as $columnDiff) {
|
||||
$message = __('Column `%s` is indexed but should not', $columnDiff);
|
||||
$indexDiff[$tableName][$columnDiff] = array(
|
||||
'message' => $message,
|
||||
'sql' => $this->generateSqlDropIndexQuery($tableName, $columnDiff),
|
||||
);
|
||||
}
|
||||
foreach ($indexes as $column => $unique) {
|
||||
if (isset($actualIndex[$tableName][$column]) && $actualIndex[$tableName][$column] != $unique) {
|
||||
if ($actualIndex[$tableName][$column]) {
|
||||
$sql = $this->generateSqlDropIndexQuery($tableName, $column);
|
||||
$sql .= '<br>' . $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $column, false);
|
||||
|
||||
$message = __('Column `%s` has unique index, but should be non unique', $column);
|
||||
} else {
|
||||
if (!$this->checkIfColumnContainsJustUniqueValues($tableName, $column)) {
|
||||
$message = __('Column `%s` should be unique index, but contains duplicate values', $column);
|
||||
$indexDiff[$tableName][$column] = array(
|
||||
'message' => $message,
|
||||
'sql' => $sql,
|
||||
);
|
||||
} else {
|
||||
if (!$this->checkIfColumnContainsJustUniqueValues($tableName, $column)) {
|
||||
$message = __('Column `%s` should be unique index, but contains duplicate values', $column);
|
||||
$indexDiff[$tableName][$column] = array(
|
||||
'message' => $message,
|
||||
'sql' => '',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql = $this->generateSqlDropIndexQuery($tableName, $column);
|
||||
$sql .= '<br>' . $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $column, true);
|
||||
|
||||
$message = __('Column `%s` should be unique index', $column);
|
||||
$indexDiff[$tableName][$column] = array(
|
||||
'message' => $message,
|
||||
'sql' => $sql,
|
||||
'sql' => '',
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
$sql = $this->generateSqlDropIndexQuery($tableName, $column);
|
||||
$sql .= '<br>' . $this->generateSqlIndexQuery($dbExpectedSchema, $tableName, $column, true);
|
||||
|
||||
$message = __('Column `%s` should be unique index', $column);
|
||||
$indexDiff[$tableName][$column] = array(
|
||||
'message' => $message,
|
||||
'sql' => $sql,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3121,21 +3120,21 @@ class Server extends AppModel
|
|||
App::uses('Folder', 'Utility');
|
||||
// check writeable directories
|
||||
$writeableDirs = array(
|
||||
'/tmp' => 0,
|
||||
APP . 'tmp' => 0,
|
||||
APP . 'files' => 0,
|
||||
APP . 'files' . DS . 'scripts' . DS . 'tmp' => 0,
|
||||
APP . 'tmp' . DS . 'csv_all' => 0,
|
||||
APP . 'tmp' . DS . 'csv_sig' => 0,
|
||||
APP . 'tmp' . DS . 'md5' => 0,
|
||||
APP . 'tmp' . DS . 'sha1' => 0,
|
||||
APP . 'tmp' . DS . 'snort' => 0,
|
||||
APP . 'tmp' . DS . 'suricata' => 0,
|
||||
APP . 'tmp' . DS . 'text' => 0,
|
||||
APP . 'tmp' . DS . 'xml' => 0,
|
||||
APP . 'tmp' . DS . 'files' => 0,
|
||||
APP . 'tmp' . DS . 'logs' => 0,
|
||||
APP . 'tmp' . DS . 'bro' => 0,
|
||||
'/tmp' => 0,
|
||||
APP . 'tmp' => 0,
|
||||
APP . 'files' => 0,
|
||||
APP . 'files' . DS . 'scripts' . DS . 'tmp' => 0,
|
||||
APP . 'tmp' . DS . 'csv_all' => 0,
|
||||
APP . 'tmp' . DS . 'csv_sig' => 0,
|
||||
APP . 'tmp' . DS . 'md5' => 0,
|
||||
APP . 'tmp' . DS . 'sha1' => 0,
|
||||
APP . 'tmp' . DS . 'snort' => 0,
|
||||
APP . 'tmp' . DS . 'suricata' => 0,
|
||||
APP . 'tmp' . DS . 'text' => 0,
|
||||
APP . 'tmp' . DS . 'xml' => 0,
|
||||
APP . 'tmp' . DS . 'files' => 0,
|
||||
APP . 'tmp' . DS . 'logs' => 0,
|
||||
APP . 'tmp' . DS . 'bro' => 0,
|
||||
);
|
||||
foreach ($writeableDirs as $path => &$error) {
|
||||
$dir = new Folder($path);
|
||||
|
|
|
@ -129,13 +129,13 @@ class ShadowAttribute extends AppModel
|
|||
'first_seen' => array(
|
||||
'rule' => array('datetimeOrNull'),
|
||||
'required' => false,
|
||||
'message' => array('Invalid ISO 8601 format')
|
||||
'message' => array('Invalid ISO 8601 format'),
|
||||
),
|
||||
'last_seen' => array(
|
||||
'datetimeOrNull' => array(
|
||||
'rule' => array('datetimeOrNull'),
|
||||
'required' => false,
|
||||
'message' => array('Invalid ISO 8601 format')
|
||||
'message' => array('Invalid ISO 8601 format'),
|
||||
),
|
||||
'validateLastSeenValue' => array(
|
||||
'rule' => array('validateLastSeenValue'),
|
||||
|
@ -173,7 +173,7 @@ class ShadowAttribute extends AppModel
|
|||
$compositeTypes = $this->getCompositeTypes();
|
||||
// explode composite types in value1 and value2
|
||||
$pieces = explode('|', $this->data['ShadowAttribute']['value']);
|
||||
if (in_array($this->data['ShadowAttribute']['type'], $compositeTypes)) {
|
||||
if (in_array($this->data['ShadowAttribute']['type'], $compositeTypes, true)) {
|
||||
if (2 != count($pieces)) {
|
||||
throw new InternalErrorException('Composite type, but value not explodable');
|
||||
}
|
||||
|
@ -300,51 +300,54 @@ class ShadowAttribute extends AppModel
|
|||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
parent::beforeValidate();
|
||||
// remove leading and trailing blanks
|
||||
//$this->trimStringFields(); // TODO
|
||||
|
||||
if (!isset($this->data['ShadowAttribute']['comment'])) {
|
||||
$this->data['ShadowAttribute']['comment'] = '';
|
||||
}
|
||||
|
||||
if (!isset($this->data['ShadowAttribute']['type'])) {
|
||||
$proposal = &$this->data['ShadowAttribute'];
|
||||
if (!isset($proposal['type'])) {
|
||||
$this->invalidate('type', 'No value provided.');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isset($proposal['comment'])) {
|
||||
$proposal['comment'] = '';
|
||||
}
|
||||
|
||||
// make some changes to the inserted value
|
||||
if (isset($this->data['ShadowAttribute']['value'])) {
|
||||
$value = trim($this->data['ShadowAttribute']['value']);
|
||||
$value = ComplexTypeTool::refangValue($value, $this->data['ShadowAttribute']['type']);
|
||||
$value = $this->Attribute->modifyBeforeValidation($this->data['ShadowAttribute']['type'], $value);
|
||||
$this->data['ShadowAttribute']['value'] = $value;
|
||||
if (isset($proposal['value'])) {
|
||||
$value = trim($proposal['value']);
|
||||
$value = ComplexTypeTool::refangValue($value, $proposal['type']);
|
||||
$value = $this->Attribute->modifyBeforeValidation($proposal['type'], $value);
|
||||
$proposal['value'] = $value;
|
||||
}
|
||||
|
||||
if (!isset($this->data['ShadowAttribute']['org'])) {
|
||||
$this->data['ShadowAttribute']['org'] = '';
|
||||
if (!isset($proposal['org'])) {
|
||||
$proposal['org'] = '';
|
||||
}
|
||||
|
||||
if (empty($this->data['ShadowAttribute']['timestamp'])) {
|
||||
$date = new DateTime();
|
||||
$this->data['ShadowAttribute']['timestamp'] = $date->getTimestamp();
|
||||
if (empty($proposal['timestamp'])) {
|
||||
$proposal['timestamp'] = time();
|
||||
}
|
||||
|
||||
if (!isset($this->data['ShadowAttribute']['proposal_to_delete'])) {
|
||||
$this->data['ShadowAttribute']['proposal_to_delete'] = 0;
|
||||
if (!isset($proposal['proposal_to_delete'])) {
|
||||
$proposal['proposal_to_delete'] = 0;
|
||||
}
|
||||
|
||||
// generate UUID if it doesn't exist
|
||||
if (empty($this->data['ShadowAttribute']['uuid'])) {
|
||||
$this->data['ShadowAttribute']['uuid'] = CakeText::uuid();
|
||||
if (empty($proposal['uuid'])) {
|
||||
$proposal['uuid'] = CakeText::uuid();
|
||||
} else {
|
||||
$this->data['ShadowAttribute']['uuid'] = strtolower($this->data['ShadowAttribute']['uuid']);
|
||||
$proposal['uuid'] = strtolower($proposal['uuid']);
|
||||
}
|
||||
|
||||
if (!empty($this->data['ShadowAttribute']['type']) && empty($this->data['ShadowAttribute']['category'])) {
|
||||
$this->data['ShadowAttribute']['category'] = $this->Attribute->typeDefinitions[$this->data['ShadowAttribute']['type']]['default_category'];
|
||||
if (empty($proposal['category'])) {
|
||||
$proposal['category'] = $this->Attribute->typeDefinitions[$proposal['type']]['default_category'];
|
||||
}
|
||||
|
||||
if (isset($proposal['first_seen'])) {
|
||||
$proposal['first_seen'] = $proposal['first_seen'] === '' ? null : $proposal['first_seen'];
|
||||
}
|
||||
if (isset($proposal['last_seen'])) {
|
||||
$proposal['last_seen'] = $proposal['last_seen'] === '' ? null : $proposal['last_seen'];
|
||||
}
|
||||
|
||||
// always return true, otherwise the object cannot be saved
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@ App::uses('AppModel', 'Model');
|
|||
* @property SharingGroupOrg $SharingGroupOrg
|
||||
* @property SharingGroupServer $SharingGroupServer
|
||||
* @property Organisation $Organisation
|
||||
* @property Event $Event
|
||||
* @property Attribute $Attribute
|
||||
* @property Thread $Thread
|
||||
*/
|
||||
class SharingGroup extends AppModel
|
||||
{
|
||||
|
@ -101,6 +104,12 @@ class SharingGroup extends AppModel
|
|||
if ($this->Attribute->hasAny(['sharing_group_id' => $this->id])) {
|
||||
return false;
|
||||
}
|
||||
if ($this->Attribute->Object->hasAny(['sharing_group_id' => $this->id])) {
|
||||
return false;
|
||||
}
|
||||
if ($this->Event->EventReport->hasAny(['sharing_group_id' => $this->id])) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,29 +1,41 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
class SharingGroupOrg extends AppModel
|
||||
{
|
||||
public $actsAs = array('AuditLog', 'Containable');
|
||||
|
||||
public $belongsTo = array(
|
||||
'SharingGroup' => array(
|
||||
'className' => 'SharingGroup',
|
||||
'foreignKey' => 'sharing_group_id'
|
||||
),
|
||||
'Organisation' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id',
|
||||
//'conditions' => array('SharingGroupElement.organisation_uuid' => 'Organisation.uuid')
|
||||
)
|
||||
'SharingGroup' => array(
|
||||
'className' => 'SharingGroup',
|
||||
'foreignKey' => 'sharing_group_id'
|
||||
),
|
||||
'Organisation' => array(
|
||||
'className' => 'Organisation',
|
||||
'foreignKey' => 'org_id',
|
||||
//'conditions' => array('SharingGroupElement.organisation_uuid' => 'Organisation.uuid')
|
||||
)
|
||||
);
|
||||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
parent::beforeValidate();
|
||||
$data = $this->data[$this->alias];
|
||||
$conditions = [
|
||||
'sharing_group_id' => $data['sharing_group_id'],
|
||||
'org_id' => $data['org_id'],
|
||||
];
|
||||
if (isset($data['id'])) {
|
||||
$conditions['id !='] = $data['id'];
|
||||
}
|
||||
if ($this->hasAny($conditions)) {
|
||||
$this->log("Trying to save duplicate organisation `{$data['org_id']}` for sharing group `{$data['sharing_group_id']}. This should never happened.");
|
||||
$this->invalidate('org_id', 'The same organisation is already assigned to this sharing group.');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function updateOrgsForSG($id, $new_orgs, $old_orgs, $user)
|
||||
{
|
||||
$log = ClassRegistry::init('Log');
|
||||
// Loop through all of the organisations we want to add.
|
||||
foreach ($new_orgs as $org) {
|
||||
$SgO = array(
|
||||
|
@ -54,16 +66,16 @@ class SharingGroupOrg extends AppModel
|
|||
}
|
||||
if ($this->save($SgO)) {
|
||||
if ($isChange) {
|
||||
$log->createLogEntry($user, 'edit', 'SharingGroupOrg', $this->id, 'Sharing group (' . $id . '): Modified right to alter sharing group for organisation (' . $org['id'] . ').', ($org['extend'] ? 'Organisation (' . $org['id'] . ') can now extend the sharing group.' : 'Organisation (' . $org['id'] . ') can no longer extend the sharing group.'));
|
||||
$this->loadLog()->createLogEntry($user, 'edit', 'SharingGroupOrg', $this->id, 'Sharing group (' . $id . '): Modified right to alter sharing group for organisation (' . $org['id'] . ').', ($org['extend'] ? 'Organisation (' . $org['id'] . ') can now extend the sharing group.' : 'Organisation (' . $org['id'] . ') can no longer extend the sharing group.'));
|
||||
} else {
|
||||
$log->createLogEntry($user, 'add', 'SharingGroupOrg', $this->id, 'Sharing group (' . $id . '): Added organisation (' . $org['id'] . ').', 'Organisation (' . $org['id'] . ') added to Sharing group.' . ($org['extend'] ? ' Organisation (' . $org['id'] . ') can extend the sharing group.' : ''));
|
||||
$this->loadLog()->createLogEntry($user, 'add', 'SharingGroupOrg', $this->id, 'Sharing group (' . $id . '): Added organisation (' . $org['id'] . ').', 'Organisation (' . $org['id'] . ') added to Sharing group.' . ($org['extend'] ? ' Organisation (' . $org['id'] . ') can extend the sharing group.' : ''));
|
||||
}
|
||||
}
|
||||
}
|
||||
// We are left with some "old orgs" that are not in the new list. This means that they can be safely deleted.
|
||||
foreach ($old_orgs as $old_org) {
|
||||
if ($this->delete($old_org['id'])) {
|
||||
$log->createLogEntry($user, 'delete', 'SharingGroupOrg', $old_org['id'], 'Sharing group (' . $id . '): Removed organisation (' . $old_org['id'] . ').', 'Organisation (' . $org['id'] . ') removed from Sharing group.');
|
||||
$this->loadLog()->createLogEntry($user, 'delete', 'SharingGroupOrg', $old_org['id'], 'Sharing group (' . $id . '): Removed organisation (' . $old_org['id'] . ').', 'Organisation (' . $org['id'] . ') removed from Sharing group.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,7 +95,12 @@ class SharingGroupOrg extends AppModel
|
|||
return $sgs;
|
||||
}
|
||||
|
||||
// pass a sharing group ID and an organisation ID, returns true if it has a matching attached organisation object
|
||||
/**
|
||||
* Pass a sharing group ID and an organisation ID, returns true if it has a matching attached organisation object
|
||||
* @param int $id
|
||||
* @param int $org_id
|
||||
* @return bool
|
||||
*/
|
||||
public function checkIfAuthorised($id, $org_id)
|
||||
{
|
||||
return $this->hasAny([
|
||||
|
|
|
@ -22,28 +22,28 @@ class Tag extends AppModel
|
|||
);
|
||||
|
||||
public $validate = array(
|
||||
'name' => array(
|
||||
'required' => array(
|
||||
'rule' => array('notBlank', 'name'),
|
||||
'message' => 'This field is required.'
|
||||
),
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty', 'name'),
|
||||
),
|
||||
'unique' => array(
|
||||
'rule' => 'isUnique',
|
||||
'message' => 'A similar name already exists.',
|
||||
),
|
||||
'name' => array(
|
||||
'required' => array(
|
||||
'rule' => array('notBlank', 'name'),
|
||||
'message' => 'This field is required.'
|
||||
),
|
||||
'colour' => array(
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty', 'colour'),
|
||||
),
|
||||
'userdefined' => array(
|
||||
'rule' => 'validateColour',
|
||||
'message' => 'Colour has to be in the RGB format (#FFFFFF)',
|
||||
),
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty', 'name'),
|
||||
),
|
||||
'unique' => array(
|
||||
'rule' => 'isUnique',
|
||||
'message' => 'A similar name already exists.',
|
||||
),
|
||||
),
|
||||
'colour' => array(
|
||||
'valueNotEmpty' => array(
|
||||
'rule' => array('valueNotEmpty', 'colour'),
|
||||
),
|
||||
'userdefined' => array(
|
||||
'rule' => 'validateColour',
|
||||
'message' => 'Colour has to be in the RGB format (#FFFFFF)',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
public $hasMany = array(
|
||||
|
@ -83,7 +83,6 @@ class Tag extends AppModel
|
|||
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
parent::beforeValidate();
|
||||
if (!isset($this->data['Tag']['org_id'])) {
|
||||
$this->data['Tag']['org_id'] = 0;
|
||||
}
|
||||
|
@ -149,8 +148,7 @@ class Tag extends AppModel
|
|||
|
||||
public function afterFind($results, $primary = false)
|
||||
{
|
||||
$results = $this->checkForOverride($results);
|
||||
return $results;
|
||||
return $this->checkForOverride($results);
|
||||
}
|
||||
|
||||
public function validateColour($fields)
|
||||
|
@ -161,12 +159,41 @@ class Tag extends AppModel
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
* @param string $tagName
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function lookupTagIdForUser(array $user, $tagName)
|
||||
{
|
||||
$conditions = ['LOWER(Tag.name)' => mb_strtolower($tagName)];
|
||||
if (!$user['Role']['perm_site_admin']) {
|
||||
$conditions['Tag.org_id'] = [0, $user['org_id']];
|
||||
$conditions['Tag.user_id'] = [0, $user['id']];
|
||||
}
|
||||
$tagId = $this->find('first', array(
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'fields' => array('Tag.id'),
|
||||
'callbacks' => false,
|
||||
));
|
||||
if (empty($tagId)) {
|
||||
return null;
|
||||
}
|
||||
return $tagId['Tag']['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $tagName
|
||||
* @return int|mixed
|
||||
*/
|
||||
public function lookupTagIdFromName($tagName)
|
||||
{
|
||||
$tagId = $this->find('first', array(
|
||||
'conditions' => array('LOWER(Tag.name)' => strtolower($tagName)),
|
||||
'conditions' => array('LOWER(Tag.name)' => mb_strtolower($tagName)),
|
||||
'recursive' => -1,
|
||||
'fields' => array('Tag.id')
|
||||
'fields' => array('Tag.id'),
|
||||
'callbacks' => false,
|
||||
));
|
||||
if (empty($tagId)) {
|
||||
return -1;
|
||||
|
@ -286,7 +313,7 @@ class Tag extends AppModel
|
|||
return array_values($tag_ids);
|
||||
}
|
||||
|
||||
public function findEventIdsByTagNames($array)
|
||||
private function findEventIdsByTagNames($array)
|
||||
{
|
||||
$ids = array();
|
||||
foreach ($array as $a) {
|
||||
|
@ -310,26 +337,6 @@ class Tag extends AppModel
|
|||
return $ids;
|
||||
}
|
||||
|
||||
public function findAttributeIdsByAttributeTagNames($array)
|
||||
{
|
||||
$ids = array();
|
||||
foreach ($array as $a) {
|
||||
$conditions['OR'][] = array('LOWER(name) LIKE' => strtolower($a));
|
||||
}
|
||||
$params = array(
|
||||
'recursive' => 1,
|
||||
'contain' => 'AttributeTag',
|
||||
'conditions' => $conditions
|
||||
);
|
||||
$result = $this->find('all', $params);
|
||||
foreach ($result as $tag) {
|
||||
foreach ($tag['AttributeTag'] as $attributeTag) {
|
||||
$ids[] = $attributeTag['attribute_id'];
|
||||
}
|
||||
}
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $tag
|
||||
* @param array $user
|
||||
|
@ -337,17 +344,18 @@ class Tag extends AppModel
|
|||
* @return false|int
|
||||
* @throws Exception
|
||||
*/
|
||||
public function captureTag($tag, $user, $force=false)
|
||||
public function captureTag(array $tag, array $user, $force=false)
|
||||
{
|
||||
$existingTag = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('LOWER(name)' => mb_strtolower($tag['name'])),
|
||||
'fields' => ['id', 'org_id', 'user_id'],
|
||||
'callbacks' => false,
|
||||
));
|
||||
if (empty($existingTag)) {
|
||||
if ($force || $user['Role']['perm_tag_editor']) {
|
||||
$this->create();
|
||||
if (!isset($tag['colour']) || empty($tag['colour'])) {
|
||||
if (empty($tag['colour'])) {
|
||||
$tag['colour'] = $this->random_color();
|
||||
}
|
||||
$tag = array(
|
||||
|
@ -363,22 +371,21 @@ class Tag extends AppModel
|
|||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (
|
||||
!$user['Role']['perm_site_admin'] &&
|
||||
}
|
||||
if (
|
||||
!$user['Role']['perm_site_admin'] &&
|
||||
(
|
||||
(
|
||||
(
|
||||
$existingTag['Tag']['org_id'] != 0 &&
|
||||
$existingTag['Tag']['org_id'] != $user['org_id']
|
||||
) ||
|
||||
(
|
||||
$existingTag['Tag']['user_id'] != 0 &&
|
||||
$existingTag['Tag']['user_id'] != $user['id']
|
||||
)
|
||||
$existingTag['Tag']['org_id'] != 0 &&
|
||||
$existingTag['Tag']['org_id'] != $user['org_id']
|
||||
) ||
|
||||
(
|
||||
$existingTag['Tag']['user_id'] != 0 &&
|
||||
$existingTag['Tag']['user_id'] != $user['id']
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return $existingTag['Tag']['id'];
|
||||
}
|
||||
|
@ -434,15 +441,21 @@ class Tag extends AppModel
|
|||
}
|
||||
|
||||
/**
|
||||
* Recover user_id from the session and override numerical_values from userSetting
|
||||
*/
|
||||
public function checkForOverride($tags)
|
||||
* Recover user_id from the session and override numerical_values from userSetting.
|
||||
*
|
||||
* @param array $tags
|
||||
* @return array
|
||||
*/
|
||||
private function checkForOverride($tags)
|
||||
{
|
||||
$userId = Configure::read('CurrentUserId');
|
||||
if ($this->tagOverrides === false && $userId > 0) {
|
||||
$this->UserSetting = ClassRegistry::init('UserSetting');
|
||||
$this->tagOverrides = $this->UserSetting->getTagNumericalValueOverride($userId);
|
||||
}
|
||||
if (empty($this->tagOverrides)) {
|
||||
return $tags;
|
||||
}
|
||||
foreach ($tags as $k => $tag) {
|
||||
if (isset($tag['Tag']['name'])) {
|
||||
$tagName = $tag['Tag']['name'];
|
||||
|
|
|
@ -231,9 +231,9 @@ class User extends AppModel
|
|||
public function __construct($id = false, $table = null, $ds = null)
|
||||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->AdminSetting = ClassRegistry::init('AdminSetting');
|
||||
$db_version = $this->AdminSetting->getSetting('db_version');
|
||||
if ($db_version >= 62) {
|
||||
|
||||
// bind AuthKey just when authkey table already exists. This is important for updating from old versions
|
||||
if (in_array('auth_keys', $this->getDataSource()->listSources(), true)) {
|
||||
$this->bindModel([
|
||||
'hasMany' => ['AuthKey']
|
||||
], false);
|
||||
|
@ -1504,4 +1504,68 @@ class User extends AppModel
|
|||
$banStatus['message'] = __('User email notification ban setting is not enabled');
|
||||
return $banStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
* @return bool
|
||||
*/
|
||||
public function hasNotifications(array $user)
|
||||
{
|
||||
$hasProposal = $this->Event->ShadowAttribute->hasAny([
|
||||
'ShadowAttribute.event_org_id' => $user['org_id'],
|
||||
'ShadowAttribute.deleted' => 0,
|
||||
]);
|
||||
if ($hasProposal) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Configure::read('MISP.delegation') && $this->_getDelegationCount($user)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $user
|
||||
* @return array
|
||||
*/
|
||||
public function populateNotifications(array $user)
|
||||
{
|
||||
$notifications = array();
|
||||
list($notifications['proposalCount'], $notifications['proposalEventCount']) = $this->_getProposalCount($user);
|
||||
$notifications['total'] = $notifications['proposalCount'];
|
||||
if (Configure::read('MISP.delegation')) {
|
||||
$notifications['delegationCount'] = $this->_getDelegationCount($user);
|
||||
$notifications['total'] += $notifications['delegationCount'];
|
||||
}
|
||||
return $notifications;
|
||||
}
|
||||
|
||||
// if not using $mode === 'full', simply check if an entry exists. We really don't care about the real count for the top menu.
|
||||
private function _getProposalCount($user, $mode = 'full')
|
||||
{
|
||||
$results[0] = $this->Event->ShadowAttribute->find('count', [
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.event_org_id' => $user['org_id'],
|
||||
'ShadowAttribute.deleted' => 0,
|
||||
)
|
||||
]);
|
||||
$results[1] = $this->Event->ShadowAttribute->find('count', [
|
||||
'conditions' => array(
|
||||
'ShadowAttribute.event_org_id' => $user['org_id'],
|
||||
'ShadowAttribute.deleted' => 0,
|
||||
),
|
||||
'fields' => 'distinct event_id'
|
||||
]);
|
||||
return $results;
|
||||
}
|
||||
|
||||
private function _getDelegationCount($user)
|
||||
{
|
||||
$this->EventDelegation = ClassRegistry::init('EventDelegation');
|
||||
return $this->EventDelegation->find('count', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array('EventDelegation.org_id' => $user['org_id'])
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
<?php
|
||||
App::uses('AppModel', 'Model');
|
||||
|
||||
/**
|
||||
* @property User $User
|
||||
*/
|
||||
class UserSetting extends AppModel
|
||||
{
|
||||
public $useTable = 'user_settings';
|
||||
|
@ -92,12 +96,14 @@ class UserSetting extends AppModel
|
|||
'event_index_hide_columns' => [
|
||||
'placeholder' => ['clusters'],
|
||||
],
|
||||
'oidc' => [ // Data saved by OIDC plugin
|
||||
'restricted' => 'perm_site_admin',
|
||||
],
|
||||
);
|
||||
|
||||
// massage the data before we send it off for validation before saving anything
|
||||
public function beforeValidate($options = array())
|
||||
{
|
||||
parent::beforeValidate();
|
||||
// add a timestamp if it is not set
|
||||
if (empty($this->data['UserSetting']['timestamp'])) {
|
||||
$this->data['UserSetting']['timestamp'] = time();
|
||||
|
@ -120,7 +126,9 @@ class UserSetting extends AppModel
|
|||
public function afterFind($results, $primary = false)
|
||||
{
|
||||
foreach ($results as $k => $v) {
|
||||
$results[$k]['UserSetting']['value'] = json_decode($v['UserSetting']['value'], true);
|
||||
if (isset($v['UserSetting']['value'])) {
|
||||
$results[$k]['UserSetting']['value'] = json_decode($v['UserSetting']['value'], true);
|
||||
}
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
@ -130,25 +138,27 @@ class UserSetting extends AppModel
|
|||
return isset($this->validSettings[$setting]);
|
||||
}
|
||||
|
||||
public function checkSettingAccess($user, $setting)
|
||||
/**
|
||||
* @param array $user
|
||||
* @param string $setting
|
||||
* @return bool|string
|
||||
*/
|
||||
public function checkSettingAccess(array $user, $setting)
|
||||
{
|
||||
if (!empty($this->validSettings[$setting]['restricted'])) {
|
||||
$role_check = $this->validSettings[$setting]['restricted'];
|
||||
if (!is_array($role_check)) {
|
||||
$role_check = array($role_check);
|
||||
$roleCheck = $this->validSettings[$setting]['restricted'];
|
||||
if (!is_array($roleCheck)) {
|
||||
$roleCheck = array($roleCheck);
|
||||
}
|
||||
$userHasValidRole = false;
|
||||
foreach ($role_check as $role) {
|
||||
foreach ($roleCheck as $role) {
|
||||
if (!empty($user['Role'][$role])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!$userHasValidRole) {
|
||||
foreach ($role_check as &$role) {
|
||||
$role = substr($role, 5);
|
||||
}
|
||||
return implode(', ', $role_check);
|
||||
foreach ($roleCheck as &$role) {
|
||||
$role = substr($role, 5);
|
||||
}
|
||||
return implode(', ', $roleCheck);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -199,7 +209,7 @@ class UserSetting extends AppModel
|
|||
return false;
|
||||
}
|
||||
|
||||
public function getDefaulRestSearchParameters($user)
|
||||
public function getDefaultRestSearchParameters($user)
|
||||
{
|
||||
return $this->getValueForUser($user['id'], 'default_restsearch_parameters') ?: [];
|
||||
}
|
||||
|
@ -232,8 +242,8 @@ class UserSetting extends AppModel
|
|||
|
||||
/**
|
||||
* Check whether the event is something the user is interested (to be alerted on)
|
||||
* @param $user
|
||||
* @param $event
|
||||
* @param array $user
|
||||
* @param array $event
|
||||
* @return bool
|
||||
*/
|
||||
public function checkPublishFilter(array $user, array $event)
|
||||
|
@ -352,7 +362,13 @@ class UserSetting extends AppModel
|
|||
return false;
|
||||
}
|
||||
|
||||
public function setSetting($user, &$data)
|
||||
/**
|
||||
* @param array $user
|
||||
* @param array $data
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setSetting(array $user, array $data)
|
||||
{
|
||||
$userSetting = array();
|
||||
if (!empty($data['UserSetting']['user_id']) && is_numeric($data['UserSetting']['user_id'])) {
|
||||
|
@ -387,21 +403,42 @@ class UserSetting extends AppModel
|
|||
} else {
|
||||
$userSetting['value'] = '';
|
||||
}
|
||||
|
||||
return $this->setSettingInternal($userSetting['user_id'], $userSetting['setting'], $userSetting['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set user setting without checking permission.
|
||||
* @param int $userId
|
||||
* @param string $setting
|
||||
* @param mixed $value
|
||||
* @return array|bool|mixed|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setSettingInternal($userId, $setting, $value)
|
||||
{
|
||||
$userSetting = [
|
||||
'user_id' => $userId,
|
||||
'setting' => $setting,
|
||||
'value' => $value,
|
||||
];
|
||||
|
||||
$existingSetting = $this->find('first', array(
|
||||
'recursive' => -1,
|
||||
'conditions' => array(
|
||||
'UserSetting.user_id' => $userSetting['user_id'],
|
||||
'UserSetting.setting' => $userSetting['setting']
|
||||
)
|
||||
'UserSetting.user_id' => $userId,
|
||||
'UserSetting.setting' => $setting,
|
||||
),
|
||||
'fields' => ['UserSetting.id'],
|
||||
'callbacks' => false,
|
||||
));
|
||||
if (empty($existingSetting)) {
|
||||
$this->create();
|
||||
} else {
|
||||
$userSetting['id'] = $existingSetting['UserSetting']['id'];
|
||||
}
|
||||
// save the setting
|
||||
$result = $this->save(array('UserSetting' => $userSetting));
|
||||
return true;
|
||||
|
||||
return $this->save($userSetting);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -86,7 +86,7 @@ class OidcAuthenticate extends BaseAuthenticate
|
|||
$this->log($mispUsername, "Unblocking user.");
|
||||
$user['disabled'] = false;
|
||||
}
|
||||
|
||||
$this->storeMetadata($user['id'], $verifiedClaims);
|
||||
$this->log($mispUsername, 'Logged in.');
|
||||
return $user;
|
||||
}
|
||||
|
@ -106,6 +106,8 @@ class OidcAuthenticate extends BaseAuthenticate
|
|||
throw new RuntimeException("Could not save user `$mispUsername` to database.");
|
||||
}
|
||||
|
||||
$this->storeMetadata($this->userModel()->id, $verifiedClaims);
|
||||
|
||||
$this->log($mispUsername, "Saved in database with ID {$this->userModel()->id}");
|
||||
$this->log($mispUsername, 'Logged in.');
|
||||
return $this->_findUser($mispUsername);
|
||||
|
@ -227,6 +229,24 @@ class OidcAuthenticate extends BaseAuthenticate
|
|||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param stdClass $verifiedClaims
|
||||
* @return array|bool|mixed|null
|
||||
* @throws Exception
|
||||
*/
|
||||
private function storeMetadata($userId, $verifiedClaims)
|
||||
{
|
||||
$value = [];
|
||||
foreach (['sub', 'preferred_username', 'given_name', 'family_name'] as $field) {
|
||||
if (property_exists($verifiedClaims, $field)) {
|
||||
$value[$field] = $verifiedClaims->{$field};
|
||||
}
|
||||
}
|
||||
|
||||
return $this->userModel()->UserSetting->setSettingInternal($userId, 'oidc', $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @param string $message
|
||||
|
|
|
@ -5,20 +5,19 @@ foreach ($warninglists as $id => $name) {
|
|||
}
|
||||
$warninglistsValues = json_encode($warninglistsValues);
|
||||
?>
|
||||
<div id="eventFilteringQBWrapper" style="padding: 5px; display: none; border: 1px solid #dddddd; border-bottom: 0px;">
|
||||
<div id="eventFilteringQBWrapper" style="padding: 5px; display: none; border: 1px solid #dddddd; border-bottom: 0;">
|
||||
<div id="eventFilteringQB" style="overflow-y: auto; padding-right: 5px; resize: vertical; max-height: 750px; height: 400px;"></div>
|
||||
<div style="display: flex; justify-content: flex-end; margin-top: 5px;">
|
||||
<input id="eventFilteringQBLinkInput" class="form-control" style="width: 66%;">
|
||||
<button id="eventFilteringQBLinkCopy" type="button" class="btn btn-inverse" style="margin-right: 5px; margin-left: 5px;" onclick="clickMessage(this);"> <i class="fa fa-clipboard"></i> <?php echo h('Copy to clipboard'); ?> </button>
|
||||
<button id="eventFilteringQBSubmit" type="button" class="btn btn-success" style="margin-right: 5px;"> <i class="fa fa-filter"></i> <?php echo h('Filter'); ?> </button>
|
||||
<button id="eventFilteringQBClear" type="button" class="btn btn-xs btn-danger" style="" title="<?php echo h('Clear filtering rules'); ?>"> <i class="fa fa-times"></i> <?php echo h('Clear'); ?> </button>
|
||||
<input id="eventFilteringQBLinkInput" class="form-control" style="width: 66%;">
|
||||
<button id="eventFilteringQBLinkCopy" type="button" class="btn btn-inverse" style="margin-right: 5px; margin-left: 5px;"> <i class="fa fa-clipboard"></i> Copy to clipboard</button>
|
||||
<button id="eventFilteringQBSubmit" type="button" class="btn btn-success" style="margin-right: 5px;"> <i class="fa fa-filter"></i> Filter</button>
|
||||
<button id="eventFilteringQBClear" type="button" class="btn btn-xs btn-danger" style="" title="Clear filtering rules"> <i class="fa fa-times"></i> Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
?>
|
||||
|
||||
<script>
|
||||
var defaultFilteringRules = <?php echo json_encode($defaultFilteringRules); ?>;
|
||||
var defaultFilteringRules = <?= json_encode($defaultFilteringRules); ?>;
|
||||
var querybuilderTool;
|
||||
function triggerEventFilteringTool(hide) {
|
||||
var qbOptions = {
|
||||
|
@ -119,9 +118,9 @@ function triggerEventFilteringTool(hide) {
|
|||
"id": "deleted",
|
||||
"label": "Deleted",
|
||||
"values": {
|
||||
0: "Deleted only",
|
||||
0: "Exclude deleted",
|
||||
1: "Both",
|
||||
2: "Exclude deleted"
|
||||
2: "Deleted only",
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -303,7 +302,7 @@ function triggerEventFilteringTool(hide) {
|
|||
<?php if (isset($filters['attributeFilter'])): ?>
|
||||
value: "<?php echo in_array($filters['attributeFilter'], array('all', 'network', 'financial', 'file')) ? h($filters['attributeFilter']) : 'all'; ?>"
|
||||
<?php else: ?>
|
||||
value: "<?php echo 'all'; ?>"
|
||||
value: 'all'
|
||||
<?php endif; ?>
|
||||
},
|
||||
<?php endif; ?>
|
||||
|
@ -339,7 +338,7 @@ function triggerEventFilteringTool(hide) {
|
|||
{
|
||||
field: 'deleted',
|
||||
id: 'deleted',
|
||||
value: <?php echo isset($filters['deleted']) ? h($filters['deleted']) : 2; ?>
|
||||
value: <?php echo isset($filters['deleted']) ? h($filters['deleted']) : 0; ?>
|
||||
},
|
||||
<?php endif; ?>
|
||||
<?php if (empty($advancedFilteringActiveRules) || isset($advancedFilteringActiveRules['includeRelatedTags'])): ?>
|
||||
|
@ -425,7 +424,6 @@ function triggerEventFilteringTool(hide) {
|
|||
},
|
||||
};
|
||||
|
||||
var filters = <?php echo json_encode($filters); ?>;
|
||||
var $wrapper = $('#eventFilteringQBWrapper');
|
||||
var $ev = $('#eventFilteringQB');
|
||||
querybuilderTool = $ev.queryBuilder(qbOptions);
|
||||
|
@ -446,6 +444,7 @@ function triggerEventFilteringTool(hide) {
|
|||
|
||||
$('#eventFilteringQBLinkCopy').off('click').on('click', function() {
|
||||
copyToClipboard($('#eventFilteringQBLinkInput'));
|
||||
clickMessage(this);
|
||||
});
|
||||
|
||||
$('#eventFilteringQBClear').off('click').on('click', function() {
|
||||
|
@ -525,27 +524,22 @@ function cleanRules(rules) {
|
|||
|
||||
function performQuery(rules) {
|
||||
var res = cleanRules(rules);
|
||||
|
||||
var url = "<?php echo $baseurl; ?>/events/viewEventAttributes/<?php echo h($event['Event']['id']); ?>";
|
||||
$.ajax({
|
||||
var url = "/events/viewEventAttributes/<?php echo h($event['Event']['id']); ?>";
|
||||
xhr({
|
||||
type: "post",
|
||||
url: url,
|
||||
data: res,
|
||||
beforeSend: function () {
|
||||
$(".loading").show();
|
||||
},
|
||||
success:function (data) {
|
||||
success: function (data) {
|
||||
$("#attributes_div").html(data);
|
||||
$(".loading").hide();
|
||||
},
|
||||
error:function() {
|
||||
error: function() {
|
||||
showMessage('fail', 'Something went wrong - could not fetch attributes.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clickMessage(clicked) {
|
||||
$clicked = $(clicked);
|
||||
var $clicked = $(clicked);
|
||||
$clicked.tooltip({
|
||||
title: 'Copied!',
|
||||
trigger: 'manual',
|
||||
|
|
|
@ -513,10 +513,10 @@
|
|||
h($me['email']),
|
||||
$this->UserName->prepend($me['email']),
|
||||
h($this->UserName->convertEmailToName($me['email'])),
|
||||
isset($notifications) ? sprintf(
|
||||
isset($hasNotifications) ? sprintf(
|
||||
'<i class="fa fa-envelope %s" role="img" aria-label="%s"></i>',
|
||||
(($notifications['total'] == 0) ? 'white' : 'red'),
|
||||
__('Notifications') . ': ' . $notifications['total']
|
||||
$hasNotifications ? 'red' : 'white',
|
||||
__('Notifications')
|
||||
) : ''
|
||||
)
|
||||
),
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 20f14c0090f1963ee485b98fa99c62f7830f734f
|
||||
Subproject commit aeb57194485cb9fa8483b6bc21308d44e921ff75
|
|
@ -1 +1 @@
|
|||
Subproject commit be3f694cd46ac26619ed8e8eaa73f45b2f62d7df
|
||||
Subproject commit 04b8c09a56b230789726bc1019efe2c304964f22
|
|
@ -7414,7 +7414,7 @@
|
|||
"character_maximum_length": null,
|
||||
"numeric_precision": "3",
|
||||
"collation_name": null,
|
||||
"column_type": "tinyint(4)",
|
||||
"column_type": "tinyint(1)",
|
||||
"column_default": "0",
|
||||
"extra": ""
|
||||
},
|
||||
|
@ -7978,12 +7978,9 @@
|
|||
},
|
||||
"object_references": {
|
||||
"id": true,
|
||||
"source_uuid": false,
|
||||
"referenced_uuid": false,
|
||||
"timestamp": false,
|
||||
"object_id": false,
|
||||
"referenced_id": false,
|
||||
"relationship_type": false
|
||||
"event_id": false
|
||||
},
|
||||
"object_relationships": {
|
||||
"id": true,
|
||||
|
@ -8062,6 +8059,7 @@
|
|||
"sharing_groups": {
|
||||
"id": true,
|
||||
"uuid": true,
|
||||
"name": true,
|
||||
"org_id": false,
|
||||
"sync_user_id": false,
|
||||
"organisation_uuid": false
|
||||
|
@ -8168,8 +8166,7 @@
|
|||
"user_settings": {
|
||||
"id": true,
|
||||
"setting": false,
|
||||
"user_id": false,
|
||||
"timestamp": false
|
||||
"user_id": false
|
||||
},
|
||||
"warninglists": {
|
||||
"id": true
|
||||
|
@ -8182,5 +8179,5 @@
|
|||
"id": true
|
||||
}
|
||||
},
|
||||
"db_version": "72"
|
||||
"db_version": "75"
|
||||
}
|
||||
|
|
|
@ -219,6 +219,7 @@ installCoreRHEL7 () {
|
|||
cd $PATH_TO_MISP
|
||||
|
||||
# Fetch submodules
|
||||
$SUDO_WWW git submodule sync
|
||||
$SUDO_WWW git submodule update --init --recursive
|
||||
# Make git ignore filesystem permission differences for submodules
|
||||
$SUDO_WWW git submodule foreach --recursive git config core.filemode false
|
||||
|
@ -237,6 +238,9 @@ installCoreRHEL7 () {
|
|||
UMASK=$(umask)
|
||||
umask 0022
|
||||
|
||||
# install python-stix dependencies
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
# install zmq
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U zmq
|
||||
|
||||
|
|
|
@ -272,6 +272,9 @@ installCoreRHEL8 () {
|
|||
UMASK=$(umask)
|
||||
umask 0022
|
||||
|
||||
# install python-stix dependencies
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
# install zmq, redis
|
||||
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U zmq redis
|
||||
|
||||
|
|
|
@ -145,6 +145,9 @@ installCore () {
|
|||
sudo mkdir /var/www/.cache/
|
||||
sudo chown ${WWW_USER}:${WWW_USER} /var/www/.cache
|
||||
|
||||
# install python-stix dependencies
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
debug "Install PyMISP"
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ${PATH_TO_MISP}/PyMISP
|
||||
|
||||
|
|
|
@ -137,6 +137,9 @@ installCore () {
|
|||
sudo mkdir /var/www/.cache/
|
||||
sudo chown ${WWW_USER}:${WWW_USER} /var/www/.cache
|
||||
|
||||
# install python-stix dependencies
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ordered-set python-dateutil six weakrefmethod
|
||||
|
||||
debug "Install PyMISP"
|
||||
${SUDO_WWW} ${PATH_TO_MISP}/venv/bin/pip install ${PATH_TO_MISP}/PyMISP
|
||||
|
||||
|
|
|
@ -212,6 +212,9 @@ coreCAKE () {
|
|||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert_age" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.block_old_event_alert_by_date" ""
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban_threshold" 5
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.event_alert_republish_ban_refresh_on_retry" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.incoming_tags_disabled_by_default" false
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.maintenance_message" "Great things are happening! MISP is undergoing maintenance, but will return shortly. You can contact the administration at \$email."
|
||||
${SUDO_WWW} ${RUN_PHP} -- ${CAKE} Admin setSetting "MISP.footermidleft" "This is an initial install"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# INSTALLATION INSTRUCTIONS
|
||||
## for OpenBSD 6.9-amd64
|
||||
## for OpenBSD 7.0-amd64
|
||||
|
||||
!!! warning
|
||||
This is not fully working yet. Mostly it is a template for our ongoing documentation efforts :spider:
|
||||
|
@ -13,11 +13,6 @@
|
|||
!!! notice
|
||||
This guide attempts to offer native httpd or apache2/nginx.
|
||||
|
||||
!!! warning
|
||||
As of 20181018 the native httpd server is NOT useable with MISP on OpenBSD 6.3.
|
||||
Thus ONLY Apache 2.x available.
|
||||
NO *rewrite* available, just yet. It will be in [the next release](https://marc.info/?l=openbsd-tech&m=152761257806283&w=2)
|
||||
|
||||
!!! notice
|
||||
As of OpenBSD 6.4 the native httpd has rewrite rules and php 5.6 is gone too.
|
||||
|
||||
|
@ -86,7 +81,7 @@ doas pkg_add -v mariadb-server
|
|||
#### Install misc dependencies
|
||||
|
||||
```bash
|
||||
doas pkg_add -v curl git python--%3.8 redis libmagic autoconf--%2.71 automake--%1.16 libtool unzip--iconv rust
|
||||
doas pkg_add -v curl git sqlite3 python--%3.9 redis libmagic autoconf--%2.71 automake--%1.16 libtool unzip--iconv rust
|
||||
```
|
||||
|
||||
```bash
|
||||
|
@ -229,8 +224,8 @@ doas rcctl enable httpd
|
|||
#### Install Python virtualenv
|
||||
```bash
|
||||
doas pkg_add -v py3-virtualenv py3-pip
|
||||
doas ln -sf /usr/local/bin/pip3.8 /usr/local/bin/pip
|
||||
doas ln -s /usr/local/bin/python3.8 /usr/local/bin/python
|
||||
doas ln -sf /usr/local/bin/pip3.9 /usr/local/bin/pip
|
||||
doas ln -s /usr/local/bin/python3.9 /usr/local/bin/python
|
||||
doas mkdir /usr/local/virtualenvs
|
||||
doas /usr/local/bin/virtualenv /usr/local/virtualenvs/MISP
|
||||
```
|
||||
|
|
|
@ -76,7 +76,7 @@ nav:
|
|||
- 'Warning': 'xINSTALL.md'
|
||||
- 'Debian 10': 'xINSTALL.debian10.md'
|
||||
- 'Tsurugi Linux': 'xINSTALL.tsurugi.md'
|
||||
- 'OpenBSD 6.8': 'xINSTALL.OpenBSD.md'
|
||||
- 'OpenBSD 7.0': 'xINSTALL.OpenBSD.md'
|
||||
- Config Guides:
|
||||
- 'Elastic Search Logging': 'CONFIG.elasticsearch-logging.md'
|
||||
- 'Amazon S3 attachments': 'CONFIG.s3-attachments.md'
|
||||
|
|
|
@ -62,6 +62,7 @@ class TestComprehensive(unittest.TestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.user_misp_connector.global_pythonify = True
|
||||
self.admin_misp_connector.global_pythonify = True
|
||||
|
||||
def test_search_index(self):
|
||||
# Search all events
|
||||
|
@ -330,7 +331,7 @@ class TestComprehensive(unittest.TestCase):
|
|||
|
||||
# Create test event
|
||||
event = create_simple_event()
|
||||
event = self.user_misp_connector.add_event(event, pythonify=True)
|
||||
event = self.user_misp_connector.add_event(event)
|
||||
check_response(event)
|
||||
|
||||
# Delete event
|
||||
|
@ -338,6 +339,64 @@ class TestComprehensive(unittest.TestCase):
|
|||
|
||||
check_response(self.admin_misp_connector.set_server_setting('MISP.enableEventBlocklisting', 0))
|
||||
|
||||
def test_deleted_attributes(self):
|
||||
# Create test event
|
||||
event = create_simple_event()
|
||||
event.add_attribute('text', "deleted", deleted=True)
|
||||
event.add_attribute('text', "not-deleted")
|
||||
event = self.user_misp_connector.add_event(event)
|
||||
check_response(event)
|
||||
|
||||
# Not deleted
|
||||
fetched_event = self.user_misp_connector.get_event(event)
|
||||
check_response(fetched_event)
|
||||
self.assertEqual(len(fetched_event.attributes), 2, fetched_event)
|
||||
|
||||
# Not deleted
|
||||
fetched_event = self.user_misp_connector.get_event(event, deleted=0)
|
||||
check_response(fetched_event)
|
||||
self.assertEqual(len(fetched_event.attributes), 2, fetched_event)
|
||||
|
||||
# Include deleted
|
||||
fetched_event = self.user_misp_connector.get_event(event, deleted=1)
|
||||
check_response(fetched_event)
|
||||
self.assertEqual(len(fetched_event.attributes), 3, fetched_event)
|
||||
|
||||
# Deleted only
|
||||
fetched_event = self.user_misp_connector.get_event(event, deleted=2)
|
||||
check_response(fetched_event)
|
||||
self.assertEqual(len(fetched_event.attributes), 1, fetched_event)
|
||||
|
||||
# Both
|
||||
fetched_event = self.user_misp_connector.get_event(event, deleted=[0, 1])
|
||||
check_response(fetched_event)
|
||||
self.assertEqual(len(fetched_event.attributes), 3, fetched_event)
|
||||
|
||||
check_response(self.user_misp_connector.delete_event(event))
|
||||
|
||||
def test_view_event_exclude_local_tags(self):
|
||||
event = create_simple_event()
|
||||
event.add_tag({"name": "local", "local": 1})
|
||||
event.add_tag({"name": "global", "local": 0})
|
||||
event.attributes[0].add_tag({"name": "local", "local": 1})
|
||||
event.attributes[0].add_tag({"name": "global", "local": 0})
|
||||
|
||||
event = self.admin_misp_connector.add_event(event)
|
||||
check_response(event)
|
||||
|
||||
event_with_local_tags = self.admin_misp_connector.get_event(event)
|
||||
check_response(event_with_local_tags)
|
||||
self.assertEqual(len(event_with_local_tags.tags), 2)
|
||||
self.assertEqual(len(event_with_local_tags.attributes[0].tags), 2)
|
||||
|
||||
event_without_local_tags = self.admin_misp_connector._check_json_response(self.admin_misp_connector._prepare_request('GET', f'events/view/{event.id}/excludeLocalTags:1'))
|
||||
check_response(event_without_local_tags)
|
||||
|
||||
self.assertEqual(event_without_local_tags["Event"]["Tag"][0]["local"], 0, event_without_local_tags)
|
||||
self.assertEqual(event_without_local_tags["Event"]["Attribute"][0]["Tag"][0]["local"], 0, event_without_local_tags)
|
||||
|
||||
check_response(self.admin_misp_connector.delete_event(event))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
|
|
@ -268,14 +268,14 @@ class TestSecurity(unittest.TestCase):
|
|||
def test_user_must_change_password(self):
|
||||
updated_user = self.admin_misp_connector.update_user({'change_pw': 1}, self.test_usr)
|
||||
check_response(updated_user)
|
||||
self.assertEqual(updated_user.change_pw, "1")
|
||||
self.assertTrue(updated_user.change_pw)
|
||||
|
||||
# Try to login, should still work because key is still valid
|
||||
PyMISP(url, self.test_usr.authkey)
|
||||
|
||||
updated_user = self.admin_misp_connector.update_user({'change_pw': 0}, self.test_usr)
|
||||
check_response(updated_user)
|
||||
self.assertEqual(updated_user.change_pw, "0")
|
||||
self.assertFalse(updated_user.change_pw)
|
||||
|
||||
# Try to login, should also still works
|
||||
PyMISP(url, self.test_usr.authkey)
|
||||
|
@ -284,7 +284,7 @@ class TestSecurity(unittest.TestCase):
|
|||
# Admin set that user must change password
|
||||
updated_user = self.admin_misp_connector.update_user({'change_pw': 1}, self.test_usr)
|
||||
check_response(updated_user)
|
||||
self.assertEqual(updated_user.change_pw, "1")
|
||||
self.assertTrue(updated_user.change_pw)
|
||||
|
||||
# User try to change back trough API
|
||||
logged_in = PyMISP(url, self.test_usr.authkey)
|
||||
|
@ -292,7 +292,7 @@ class TestSecurity(unittest.TestCase):
|
|||
|
||||
updated_user = self.admin_misp_connector.get_user(self.test_usr)
|
||||
# Should not be possible
|
||||
self.assertEqual(updated_user.change_pw, "1")
|
||||
self.assertTrue(updated_user.change_pw)
|
||||
|
||||
def test_disabled_user(self):
|
||||
# Disable user
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
from pymisp import PyMISP, MISPEvent
|
||||
from pymisp import PyMISP, MISPEvent, MISPGalaxyCluster
|
||||
|
||||
|
||||
def check_response(response):
|
||||
|
@ -53,6 +53,24 @@ check_response(event)
|
|||
# Publish that event
|
||||
check_response(pymisp.publish(event))
|
||||
|
||||
# Publish event inline
|
||||
url = f'events/publish/{event.id}/disable_background_processing:1'
|
||||
push_event = pymisp._check_json_response(pymisp._prepare_request('POST', url))
|
||||
check_response(push_event)
|
||||
|
||||
# Create testing galaxy cluster
|
||||
galaxy = pymisp.galaxies()[0]
|
||||
galaxy_cluster = MISPGalaxyCluster()
|
||||
galaxy_cluster.value = "Test Cluster"
|
||||
galaxy_cluster.authors = ["MISP"]
|
||||
galaxy_cluster.distribution = 1
|
||||
galaxy_cluster.description = "Example test cluster"
|
||||
galaxy_cluster = pymisp.add_galaxy_cluster(galaxy.id, galaxy_cluster)
|
||||
check_response(galaxy_cluster)
|
||||
|
||||
# Publish that galaxy cluster
|
||||
check_response(pymisp.publish_galaxy_cluster(galaxy_cluster))
|
||||
|
||||
# Preview event
|
||||
url = f'servers/previewEvent/{remote_server["id"]}/{event.uuid}'
|
||||
event_preview = pymisp._check_json_response(pymisp._prepare_request('GET', url))
|
||||
|
@ -92,3 +110,4 @@ check_response(rules_response)
|
|||
check_response(pymisp.delete_server(remote_server))
|
||||
check_response(pymisp.delete_event(event))
|
||||
check_response(pymisp.delete_event_blocklist(event))
|
||||
check_response(pymisp.delete_galaxy_cluster(galaxy_cluster))
|
||||
|
|
Loading…
Reference in New Issue