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

pull/5259/head
chrisr3d 2019-10-03 10:43:39 +02:00
commit 3b3a1e0067
43 changed files with 31106 additions and 15032 deletions

View File

@ -57,6 +57,7 @@ CREATE TABLE IF NOT EXISTS `attribute_tags` (
`attribute_id` int(11) NOT NULL,
`event_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
`local` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `attribute_id` (`attribute_id`),
INDEX `event_id` (`event_id`),
@ -120,6 +121,60 @@ CREATE TABLE IF NOT EXISTS `correlations` (
INDEX `a_sharing_group_id` (`a_sharing_group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE IF NOT EXISTS decaying_models (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) COLLATE utf8_bin DEFAULT NULL,
`name` varchar(255) COLLATE utf8_bin NOT NULL,
`parameters` text,
`attribute_types` text,
`description` text,
`org_id` int(11),
`enabled` tinyint(1) NOT NULL DEFAULT 0,
`all_orgs` tinyint(1) NOT NULL DEFAULT 1,
`ref` text COLLATE utf8_unicode_ci,
`formula` varchar(255) COLLATE utf8_bin NOT NULL,
`version` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
`default` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
INDEX `uuid` (`uuid`),
INDEX `name` (`name`),
INDEX `org_id` (`org_id`),
INDEX `enabled` (`enabled`),
INDEX `all_orgs` (`all_orgs`),
INDEX `version` (`version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS decaying_model_mappings (
`id` int(11) NOT NULL AUTO_INCREMENT,
`attribute_type` varchar(255) COLLATE utf8_bin NOT NULL,
`model_id` int(11) NOT NULL,
PRIMARY KEY (id),
INDEX `model_id` (`model_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
-- Table structure for table `event_graph`
--
CREATE TABLE IF NOT EXISTS event_graph (
`id` int(11) NOT NULL AUTO_INCREMENT,
`event_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`org_id` int(11) NOT NULL,
`timestamp` int(11) NOT NULL DEFAULT 0,
`network_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci,
`network_json` MEDIUMTEXT NOT NULL,
`preview_img` MEDIUMTEXT,
PRIMARY KEY (id),
INDEX `event_id` (`event_id`),
INDEX `user_id` (`user_id`),
INDEX `org_id` (`org_id`),
INDEX `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
@ -219,6 +274,7 @@ CREATE TABLE IF NOT EXISTS `event_tags` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`event_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
`local` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `event_id` (`event_id`),
INDEX `tag_id` (`tag_id`)
@ -268,6 +324,7 @@ CREATE TABLE IF NOT EXISTS `feeds` (
`lookup_visible` tinyint(1) DEFAULT 0,
`headers` TEXT COLLATE utf8_bin,
`caching_enabled` tinyint(1) NOT NULL DEFAULT 0,
`force_to_ids` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `input_source` (`input_source`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
@ -303,6 +360,7 @@ CREATE TABLE IF NOT EXISTS `galaxies` (
`version` varchar(255) COLLATE utf8_bin NOT NULL,
`icon` VARCHAR(255) COLLATE utf8_bin NOT NULL DEFAULT '',
`namespace` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT "misp",
`kill_chain_order` text,
PRIMARY KEY (id),
INDEX `name` (`name`),
INDEX `uuid` (`uuid`),
@ -319,7 +377,8 @@ CREATE TABLE IF NOT EXISTS `galaxies` (
CREATE TABLE IF NOT EXISTS `galaxy_clusters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uuid` varchar(255) COLLATE utf8_bin NOT NULL,
`uuid` varchar(255) COLLATE utf8_bin NOT NULL default '',
`collection_uuid` varchar(255) COLLATE utf8_bin NOT NULL,
`type` varchar(255) COLLATE utf8_bin NOT NULL,
`value` text COLLATE utf8_bin NOT NULL,
`tag_name` varchar(255) COLLATE utf8_bin NOT NULL DEFAULT '',
@ -331,6 +390,7 @@ CREATE TABLE IF NOT EXISTS `galaxy_clusters` (
PRIMARY KEY (id),
INDEX `value` (`value`(255)),
INDEX `uuid` (`uuid`),
INDEX `collection_uuid` (`collection_uuid`),
INDEX `galaxy_id` (`galaxy_id`),
INDEX `version` (`version`),
INDEX `tag_name` (`tag_name`),
@ -467,6 +527,16 @@ CREATE TABLE IF NOT EXISTS `noticelist_entries` (
INDEX `noticelist_id` (`noticelist_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `notification_logs` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`org_id` int(11) NOT NULL,
`type` varchar(255) COLLATE utf8_bin NOT NULL,
`timestamp` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
KEY `org_id` (`org_id`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- -------------------------------------------------------
--
@ -532,7 +602,8 @@ CREATE TABLE IF NOT EXISTS `object_references` (
`referenced_type` int(11) NOT NULL DEFAULT 0,
`relationship_type` varchar(255) CHARACTER SET utf8 COLLATE utf8_unicode_ci,
`comment` text COLLATE utf8_bin NOT NULL,
`deleted` TINYINT NOT NULL DEFAULT 0,
`deleted` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
INDEX `source_uuid` (`source_uuid`),
INDEX `referenced_uuid` (`referenced_uuid`),
@ -662,6 +733,27 @@ CREATE TABLE IF NOT EXISTS `posts` (
INDEX `thread_id` (`thread_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `rest_client_histories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`org_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`headers` text,
`body` text,
`url` text,
`http_method` varchar(255),
`timestamp` int(11) NOT NULL DEFAULT 0,
`use_full_path` tinyint(1) DEFAULT 0,
`show_result` tinyint(1) DEFAULT 0,
`skip_ssl` tinyint(1) DEFAULT 0,
`outcome` int(11) NOT NULL,
`bookmark` tinyint(1) NOT NULL DEFAUlT 0,
`bookmark_name` varchar(255) NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `org_id` (`org_id`),
KEY `user_id` (`user_id`),
KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
@ -741,8 +833,12 @@ CREATE TABLE IF NOT EXISTS `servers` (
`cert_file` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`client_cert_file` varchar(255) COLLATE utf8_bin DEFAULT NULL,
`internal` tinyint(1) NOT NULL DEFAULT 0,
`skip_proxy` tinyint(1) NOT NULL DEFAULT 0,
`caching_enabled` tinyint(1) NOT NULL DEFAULT 0,
`priority` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `org_id` (`org_id`),
INDEX `priority` (`priority`),
INDEX `remote_org_id` (`remote_org_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
@ -895,6 +991,29 @@ CREATE TABLE IF NOT EXISTS `sightings` (
INDEX `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
CREATE TABLE IF NOT EXISTS tag_collections (
`id` int(11) NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) COLLATE utf8_bin DEFAULT NULL,
`user_id` int(11) NOT NULL,
`org_id` int(11) NOT NULL,
`name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`description` TEXT CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`all_orgs` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (id),
INDEX `uuid` (`uuid`),
INDEX `user_id` (`user_id`),
INDEX `org_id` (`org_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS tag_collection_tags (
`id` int(11) NOT NULL AUTO_INCREMENT,
`tag_collection_id` int(11) NOT NULL,
`tag_id` int(11) NOT NULL,
PRIMARY KEY (id),
INDEX `uuid` (`tag_collection_id`),
INDEX `user_id` (`tag_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
@ -909,10 +1028,12 @@ CREATE TABLE IF NOT EXISTS `tags` (
`org_id` int(11) NOT NULL DEFAULT 0,
`user_id` int(11) NOT NULL DEFAULT 0,
`hide_tag` tinyint(1) NOT NULL DEFAULT 0,
`numerical_value` int(11) NULL,
PRIMARY KEY (`id`),
INDEX `name` (`name`(255)),
INDEX `org_id` (`org_id`),
INDEX `user_id` (`user_id`)
INDEX `user_id` (`user_id`),
INDEX `numerical_value` (`numerical_value`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
@ -946,6 +1067,8 @@ CREATE TABLE IF NOT EXISTS `taxonomies` (
`description` text COLLATE utf8_bin NOT NULL,
`version` int(11) NOT NULL,
`enabled` tinyint(1) NOT NULL DEFAULT 0,
`exclusive` tinyint(1) DEFAULT 0,
`required` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
@ -961,8 +1084,11 @@ CREATE TABLE IF NOT EXISTS `taxonomy_entries` (
`value` text COLLATE utf8_bin NOT NULL,
`expanded` text COLLATE utf8_bin,
`colour` varchar(7) CHARACTER SET utf8 COLLATE utf8_bin,
`description` text CHARACTER SET UTF8 collate utf8_bin,
`numerical_value` int(11) NULL,
PRIMARY KEY (`id`),
INDEX `taxonomy_predicate_id` (`taxonomy_predicate_id`)
INDEX `taxonomy_predicate_id` (`taxonomy_predicate_id`),
INDEX `numerical_value` (`numerical_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- --------------------------------------------------------
@ -977,8 +1103,12 @@ CREATE TABLE IF NOT EXISTS `taxonomy_predicates` (
`value` text COLLATE utf8_bin NOT NULL,
`expanded` text COLLATE utf8_bin,
`colour` varchar(7) CHARACTER SET utf8 COLLATE utf8_bin,
`description` text CHARACTER SET UTF8 collate utf8_bin,
`exclusive` tinyint(1) DEFAULT 0,
`numerical_value` int(11) NULL,
PRIMARY KEY (`id`),
INDEX `taxonomy_id` (`taxonomy_id`)
INDEX `taxonomy_id` (`taxonomy_id`),
INDEX `numerical_value` (`numerical_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
-- --------------------------------------------------------
@ -1113,6 +1243,18 @@ CREATE TABLE IF NOT EXISTS `threat_levels` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE IF NOT EXISTS `user_settings` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`setting` varchar(255) COLLATE utf8_bin NOT NULL,
`value` text COLLATE utf8_bin NOT NULL,
`user_id` int(11) NOT NULL,
`timestamp` int(11) NOT NULL,
INDEX `setting` (`setting`),
INDEX `user_id` (`user_id`),
INDEX `timestamp` (`timestamp`),
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- --------------------------------------------------------
--
@ -1212,7 +1354,7 @@ CREATE TABLE IF NOT EXISTS `whitelist` (
--
INSERT INTO `admin_settings` (`id`, `setting`, `value`) VALUES
(1, 'db_version', '11');
(1, 'db_version', '40');
INSERT INTO `feeds` (`id`, `provider`, `name`, `url`, `distribution`, `default`, `enabled`) VALUES
(1, 'CIRCL', 'CIRCL OSINT Feed', 'https://www.circl.lu/doc/misp/feed-osint', 3, 1, 0),

2
PyMISP

@ -1 +1 @@
Subproject commit b67cec60a3c611efb96f69fda3ef92c3ce740eea
Subproject commit de6a64ba45b56cef1a233df306da411c49801c03

View File

@ -463,7 +463,11 @@ class AppController extends Controller
}
$this->set('loggedInUserName', $this->__convertEmailToName($this->Auth->user('email')));
$notifications = $this->{$this->modelClass}->populateNotifications($this->Auth->user());
if ($this->request->params['controller'] === 'users' && $this->request->params['action'] === 'dashboard') {
$notifications = $this->{$this->modelClass}->populateNotifications($this->Auth->user());
} else {
$notifications = $this->{$this->modelClass}->populateNotifications($this->Auth->user(), 'fast');
}
$this->set('notifications', $notifications);
$this->ACL->checkAccess($this->Auth->user(), Inflector::variable($this->request->params['controller']), $this->action);
}

View File

@ -3067,6 +3067,7 @@ class AttributesController extends AppController
$this->Auth->user(),
array(
'conditions' => array('Attribute.id' => $id, 'Attribute.deleted' => 0),
'flatten' => 1,
'contain' => array('Event.orgc_id')
)
);

View File

@ -551,6 +551,13 @@ class ACLComponent extends Component
'verifyGPG' => array(),
'view' => array('*'),
),
'userSettings' => array(
'index' => array('*'),
'view' => array('*'),
'setSetting' => array('*'),
'getSetting' => array('*'),
'delete' => array('*')
),
'warninglists' => array(
'checkValue' => array('perm_auth'),
'delete' => array(),

View File

@ -249,6 +249,17 @@ class RestResponseComponent extends Component
'http_method' => 'GET'
)
),
'UserSetting' => array(
'setSetting' => array(
'description' => "POST a User setting object in JSON format to this API to create a new setting or update the equivalent existing setting. Admins/site admins can specify a user ID besides their own.",
'mandatory' => array('setting', 'value'),
'optional' => array('user_id')
),
'delete' => array(
'description' => "POST or DELETE to this API to delete an existing setting.",
'params' => array('id')
)
),
'Warninglist' => array(
'checkValue' => array(
'description' => "POST a JSON list with value(s) to check against the warninglists to get a JSON dictionary as a response with any hits, if there are any (with the key being the passed value triggering a warning).",
@ -1548,10 +1559,12 @@ class RestResponseComponent extends Component
$fieldsConstraint[$sf]['label'] = $label;
}
} else {
$fieldsConstraint[$field] = $this->__fieldsConstraint[$field];
$label = $scope . '.' . $field;
$fieldsConstraint[$field]['id'] = $label;
$fieldsConstraint[$field]['label'] = $label;
if (!empty($this->__fieldsConstraint[$field])) {
$fieldsConstraint[$field] = $this->__fieldsConstraint[$field];
$label = $scope . '.' . $field;
$fieldsConstraint[$field]['id'] = $label;
$fieldsConstraint[$field]['label'] = $label;
}
}
// add dynamic data and overwrite name collisions

View File

@ -132,7 +132,10 @@ class FeedsController extends AppController
public function importFeeds()
{
if ($this->request->is('post')) {
$results = $this->Feed->importFeeds($this->request->data['Feed']['json'], $this->Auth->user());
if (isset($this->request->data['Feed']['json'])) {
$this->request->data = $this->request->data['Feed']['json'];
}
$results = $this->Feed->importFeeds($this->request->data, $this->Auth->user());
if ($results['successes'] > 0) {
$flashType = 'success';
$message = $results['successes'] . ' new feeds added.';
@ -505,8 +508,15 @@ class FeedsController extends AppController
}
}
}
$this->Flash->success($message);
$this->redirect(array('action' => 'index'));
if (!isset($message)) {
$message = __('No feed enabled.');
}
if ($this->_isRest()) {
return $this->RestResponse->viewData(array('result' => $message), $this->response->type());
} else {
$this->Flash->success($message);
$this->redirect(array('action' => 'index'));
}
}
public function getEvent($feedId, $eventUuid, $all = false)

View File

@ -981,14 +981,14 @@ class TagsController extends AppController
$date = new DateTime();
$tempObject[$objectType]['timestamp'] = $date->getTimestamp();
$this->$objectType->save($tempObject);
if ($objectType === 'Attribute') {
$this->$objectType->Event->unpublishEvent($object['Event']['id']);
} else if ($objectType === 'Event') {
$this->Event->unpublishEvent($object['Event']['id']);
}
if($local) {
$message = 'Local tag ' . $existingTag['Tag']['name'] . '(' . $existingTag['Tag']['id'] . ') successfully attached to ' . $objectType . '(' . $object[$objectType]['id'] . ').';
} else {
if ($objectType === 'Attribute') {
$this->$objectType->Event->unpublishEvent($object['Event']['id']);
} else if ($objectType === 'Event') {
$this->Event->unpublishEvent($object['Event']['id']);
}
$message = 'Global tag ' . $existingTag['Tag']['name'] . '(' . $existingTag['Tag']['id'] . ') successfully attached to ' . $objectType . '(' . $object[$objectType]['id'] . ').';
}
return $this->RestResponse->saveSuccessResponse('Tags', 'attachTagToObject', false, $this->response->type(), $message);

View File

@ -0,0 +1,333 @@
<?php
/*
*
* Feature developed as part of a training given by CIRCL in Luxembourg on 26/09/2019
* Verbose comments for educational purposes only
*
*/
App::uses('AppController', 'Controller');
class UserSettingsController extends AppController
{
public $components = array('Session', 'RequestHandler');
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999,
'order' => array(
'UserSetting.id' => 'DESC'
),
'contain' => array(
'User.id',
'User.email'
)
);
public function index()
{
$filterData = array(
'request' => $this->request,
'paramArray' => array('setting', 'user_id', 'sort', 'direction', 'page', 'limit'),
'named_params' => $this->params['named']
);
$exception = false;
$filters = $this->_harvestParameters($filterData, $exception);
$conditions = array();
if (!empty($filters['setting'])) {
$conditions['AND'][] = array(
'setting' => $filters['setting']
);
}
if (!empty($filters['user_id'])) {
if ($filters['user_id'] === 'all') {
$context = 'all';
} else if ($filters['user_id'] === 'me') {
$conditions['AND'][] = array(
'user_id' => $this->Auth->user('id')
);
$context = 'me';
} else if ($filters['user_id'] === 'org') {
$conditions['AND'][] = array(
'user_id' => $this->UserSetting->User->find(
'list', array(
'conditions' => array(
'User.org_id' => $this->Auth->user('org_id')
),
'fields' => array(
'User.id', 'User.id'
)
)
)
);
$context = 'org';
} else {
$conditions['AND'][] = array(
'user_id' => $filters['user_id']
);
}
}
if (!$this->_isSiteAdmin()) {
if ($this->_isAdmin()) {
$conditions['AND'][] = array(
'UserSetting.user_id' => $this->UserSetting->User->find(
'list', array(
'conditions' => array(
'User.org_id' => $this->Auth->user('org_id')
),
'fields' => array(
'User.id', 'User.id'
)
)
)
);
} else {
$conditions['AND'][] = array(
'UserSetting.user_id' => $this->Auth->user('id')
);
}
}
if ($this->_isRest()) {
$params = array(
'conditions' => $conditions
);
if (!empty($filters['page'])) {
$params['page'] = $filters['page'];
$params['limit'] = $this->paginate['limit'];
}
if (!empty($filters['limit'])) {
$params['limit'] = $filters['limit'];
}
$userSettings = $this->UserSetting->find('all', $params);
return $this->RestResponse->viewData($userSettings, $this->response->type());
} else {
$this->paginate['conditions'] = $conditions;
$this->set('data', $this->paginate());
$this->set('context', empty($context) ? 'null' : $context);
}
}
public function view($id)
{
// check if the ID is valid and whether a user setting with the given ID exists
if (empty($id) || !is_numeric($id)) {
throw new InvalidArgumentException(__('Invalid ID passed.'));
}
$userSetting = $this->UserSetting->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.id' => $id
),
'contain' => array('User.id', 'User.org_id')
));
if (empty($userSetting)) {
throw new NotFoundException(__('Invalid user setting.'));
}
$checkAccess = $this->UserSetting->checkAccess($this->Auth->user(), $userSetting);
if (!$checkAccess) {
throw new NotFoundException(__('Invalid user setting.'));
}
if ($this->_isRest()) {
unset($userSetting['User']);
return $this->RestResponse->viewData($userSetting, $this->response->type());
} else {
$this->set($data, $userSetting);
}
}
public function setSetting($user_id = false, $setting = false)
{
// handle POST requests
if ($this->request->is('post')) {
// massage the request to allow for unencapsulated POST requests via the API
// {"key": "value"} instead of {"UserSetting": {"key": "value"}}
if (empty($this->request->data['UserSetting'])) {
$this->request->data = array('UserSetting' => $this->request->data);
}
if (!empty($user_id)) {
$this->request->data['UserSetting']['user_id'] = $user_id;
}
if (!empty($setting)) {
$this->request->data['UserSetting']['setting'] = $setting;
}
// force our user's ID as the user ID in all cases
$userSetting = array(
'user_id' => $this->Auth->user('id')
);
if (!empty($this->request->data['UserSetting']['user_id']) && is_numeric($this->request->data['UserSetting']['user_id'])) {
$user = $this->UserSetting->User->find('first', array(
'recursive' => -1,
'conditions' => array('User.id' => $this->request->data['UserSetting']['user_id']),
'fields' => array('User.org_id')
));
if (
$this->_isSiteAdmin() ||
($this->_isAdmin() && ($user['User']['org_id'] == $this->Auth->user('org_id')))
) {
$userSetting['user_id'] = $this->request->data['UserSetting']['user_id'];
}
}
if (empty($this->request->data['UserSetting']['setting'])) {
throw new MethodNotAllowedException(__('This endpoint expects both a setting and a value to be set.'));
} else {
if (!$this->UserSetting->checkSettingValidity($this->request->data['UserSetting']['setting'])) {
throw new MethodNotAllowedException(__('Invalid setting.'));
}
$userSetting['setting'] = $this->request->data['UserSetting']['setting'];
}
$userSetting['value'] = empty($this->request->data['UserSetting']['value']) ? '' :
json_encode(json_decode($this->request->data['UserSetting']['value'], true));
$existingSetting = $this->UserSetting->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.user_id' => $userSetting['user_id'],
'UserSetting.setting' => $userSetting['setting']
)
));
if (empty($existingSetting)) {
$this->UserSetting->create();
} else {
$userSetting['id'] = $existingSetting['UserSetting']['id'];
}
// save the setting
$result = $this->UserSetting->save(array('UserSetting' => $userSetting));
if ($result) {
// if we've managed to save our setting
if ($this->_isRest()) {
// if we are dealing with an API request
$userSetting = $this->UserSetting->find('first', array(
'recursive' => -1,
'conditions' => array('UserSetting.id' => $this->UserSetting->id)
));
return $this->RestResponse->viewData($userSetting, $this->response->type());
} else {
// if we are dealing with a UI request, redirect the user to the user view with the proper flash message
$this->Flash->success(__('Setting saved.'));
$this->redirect(array('controller' => 'user_settings', 'action' => 'index', $this->Auth->User('id')));
}
} else {
// if we've failed saving our setting
if ($this->_isRest()) {
// if we are dealing with an API request
return $this->RestResponse->saveFailResponse('UserSettings', 'add', false, $this->UserSetting->validationErrors, $this->response->type());
} else {
/*
* if we are dealing with a UI request, simply set an error in a flash message
* and render the view of this endpoint, pre-populated with the submitted values.
*/
$this->Flash->error(__('Setting could not be saved.'));
}
}
}
if ($this->_isRest()) {
// GET request via the API should describe the endpoint
return $this->RestResponse->describe('UserSettings', 'setSetting', false, $this->response->type());
} else {
// load the valid settings from the model
$validSettings = $this->UserSetting->validSettings;
if ($this->_isSiteAdmin()) {
$users = $this->UserSetting->User->find('list', array(
'recursive' => -1,
'fields' => array('User.id', 'User.email')
));
} else if ($this->_isAdmin()) {
$users = $this->UserSetting->User->find('list', array(
'recursive' => -1,
'conditions' => array('User.org_id' => $this->Auth->user('org_id')),
'fields' => array('User.id', 'User.email')
));
} else {
$users = array($this->Auth->user('id') => $this->Auth->user('email'));
}
if (!empty($user_id) && $this->request->is('get')) {
$this->request->data['UserSetting']['user_id'] = $user_id;
}
$this->set('users', $users);
$this->set('validSettings', $validSettings);
}
}
public function getSetting($user_id, $setting)
{
if (!$this->UserSetting->checkSettingValidity($setting)) {
throw new MethodNotAllowedException(__('Invalid setting.'));
}
$userSetting = $this->UserSetting->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.user_id' => $user_id,
'UserSetting.setting' => $setting
),
'contain' => array('User.id', 'User.org_id')
));
$checkAccess = $this->UserSetting->checkAccess($this->Auth->user(), $userSetting, $user_id);
if (empty($checkAccess)) {
throw new MethodNotAllowedException(__('Invalid setting.'));
}
if (!empty($userSetting)) {
$userSetting = json_encode($userSetting['UserSetting']['value']);
} else {
$userSetting = '[]';
}
return $this->RestResponse->viewData($userSetting, $this->response->type(), false, true);
}
public function delete($id = false)
{
if ($this->request->is('get') && $this->_isRest()) {
/*
* GET request via the API should describe the endpoint
* Unlike with the add() endpoint, we want to run this check before doing anything else,
* in order to allow us to reach this endpoint without passing a valid ID
*/
return $this->RestResponse->describe('UserSettings', 'delete', false, $this->response->type());
}
// check if the ID is valid and whether a user setting with the given ID exists
if (empty($id) || !is_numeric($id)) {
throw new InvalidArgumentException(__('Invalid ID passed.'));
}
$userSetting = $this->UserSetting->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.id' => $id
),
'contain' => array('User.id', 'User.org_id')
));
if (empty($userSetting)) {
throw new NotFoundException(__('Invalid user setting.'));
}
$checkAccess = $this->UserSetting->checkAccess($this->Auth->user(), $userSetting);
if (!$checkAccess) {
throw new NotFoundException(__('Invalid user setting.'));
}
if ($this->request->is('post') || $this->request->is('delete')) {
// Delete the setting that we were after.
$result = $this->UserSetting->delete($userSetting['UserSetting']['id']);
if ($result) {
// set the response for both the UI and API
$message = __('Setting deleted.');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('UserSettings', 'delete', $id, $this->response->type(), $message);
} else {
$this->Flash->success($message);
}
} else {
// set the response for both the UI and API
$message = __('Setting could not be deleted.');
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('UserSettings', 'delete', $id, $message, $this->response->type());
} else {
$this->Flash->error($message);
}
}
/*
* The API responses stopped executing this function and returned a serialised response to the user.
* For UI users, redirect to where they issued the request from.
*/
$this->redirect($this->referer());
} else {
throw new MethodNotAllowedException(__('Expecting POST or DELETE request.'));
}
}
}

View File

@ -6,7 +6,6 @@ class SyncTool
public function setupHttpSocket($server = null)
{
$params = array();
App::uses('HttpSocket', 'Network/Http');
if (!empty($server)) {
if ($server['Server']['cert_file']) {
$params['ssl_cafile'] = APP . "files" . DS . "certs" . DS . $server['Server']['id'] . '.pem';
@ -22,20 +21,33 @@ class SyncTool
}
}
}
$HttpSocket = new HttpSocket($params);
if (empty($server['Server']['skip_proxy'])) {
$proxy = Configure::read('Proxy');
if (isset($proxy['host']) && !empty($proxy['host'])) {
$HttpSocket->configProxy($proxy['host'], $proxy['port'], $proxy['method'], $proxy['user'], $proxy['password']);
}
}
return $HttpSocket;
return $this->createHttpSocket($params);
}
public function setupHttpSocketFeed($feed = null)
{
return $this->setupHttpSocket();
}
/**
* @param array $params
* @return HttpSocket
* @throws Exception
*/
private function createHttpSocket($params = array())
{
// Use own CA PEM file
$caPath = Configure::read('MISP.ca_path');
if (!isset($params['ssl_cafile']) && $caPath) {
if (!file_exists($caPath)) {
throw new Exception("CA file '$caPath' doesn't exists.");
}
$params['ssl_cafile'] = $caPath;
}
App::uses('HttpSocket', 'Network/Http');
$HttpSocket = new HttpSocket();
$HttpSocket = new HttpSocket($params);
$proxy = Configure::read('Proxy');
if (isset($proxy['host']) && !empty($proxy['host'])) {
$HttpSocket->configProxy($proxy['host'], $proxy['port'], $proxy['method'], $proxy['user'], $proxy['password']);

@ -1 +1 @@
Subproject commit c4a51509c554a0762e8b4d9b3985fe042b445fe7
Subproject commit d2e1681eb8ec75e6c2819fa113834843fed6995a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
msgid ""
msgstr ""
"Project-Id-Version: misp\n"
"PO-Revision-Date: 2019-07-04 09:30\n"
"PO-Revision-Date: 2019-09-30 01:23\n"
"Last-Translator: Steve Clement (SteveClement)\n"
"Language-Team: Norwegian\n"
"MIME-Version: 1.0\n"
@ -3891,8 +3891,8 @@ msgid "The debug level of the instance for site admins. This feature allows site
msgstr "Feilsøkingsnivået for forekomsten for nettstedadministratorer. Denne funksjonen tillater at webansvarlige kan kjøre feilsøkingsmodus på en levende forekomst uten å utsette den for andre brukere. Det mest fordelaktige alternativet for feilsøking og site_admin_debug brukes til administratorer på nettstedet."
#: Model/Server.php:2254
msgid "Failed (partially?) because of errors: "
msgstr "Mislyktes (delvis?) På grunn av feil: "
msgid "Failed (partially?) because of validation errors: "
msgstr "Mislyktes (delvis?) På grunn av valideringsfeil: "
#: Model/Server.php:2258
msgid "Blocked an edit to an event that was created locally. This can happen if a synchronised event that was created on this instance was modified by an administrator on the remote side."
@ -15945,8 +15945,8 @@ msgstr "Synkroniser brukeren for"
#: View/Users/admin_add.ctp:70
#: View/Users/admin_edit.ctp:64
#: View/Users/edit.ctp:23
msgid "Paste the user's GnuPG key here or try to retrieve it from the CIRCL key server by clicking on \"Fetch GnuPG key\" below."
msgstr "Lim inn brukerens GnuPG-nøkkel her, eller prøv å hente den fra CIRCL-nøkkelserveren ved å klikke på \"Hent GnuPG-nøkkel\" nedenfor."
msgid "Paste the user's GnuPG key here or try to retrieve it from the MIT key server by clicking on \"Fetch GnuPG key\" below."
msgstr "Lim inn brukerens GnuPG-nøkkel her, eller prøv å hente den fra MIT-nøkkelserveren ved å klikke på \"Hent GnuPG-nøkkel\" nedenfor."
#: View/Users/admin_add.ctp:72
#: View/Users/admin_edit.ctp:66

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -75,7 +75,8 @@ class AppModel extends Model
13 => false, 14 => false, 15 => false, 18 => false, 19 => false, 20 => false,
21 => false, 22 => false, 23 => false, 24 => false, 25 => false, 26 => false,
27 => false, 28 => false, 29 => false, 30 => false, 31 => false, 32 => false,
33 => false, 34 => false, 35 => false, 36 => false, 37 => false, 38 => false
33 => false, 34 => false, 35 => false, 36 => false, 37 => false, 38 => false,
39 => false, 40 => false
);
public $advanced_updates_description = array(
@ -1246,6 +1247,23 @@ class AppModel extends Model
$sqlArray[] = "ALTER TABLE servers ADD priority int(11) NOT NULL DEFAULT 0;";
$indexArray[] = array('servers', 'priority');
break;
case 39:
$sqlArray[] = "CREATE TABLE IF NOT EXISTS user_settings (
`id` int(11) NOT NULL AUTO_INCREMENT,
`key` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
`value` text,
`user_id` int(11) NOT NULL,
`timestamp` int(11) NOT NULL,
PRIMARY KEY (id),
INDEX `key` (`key`),
INDEX `user_id` (`user_id`),
INDEX `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;";
break;
case 40:
$sqlArray[] = "ALTER TABLE `user_settings` ADD `timestamp` int(11) NOT NULL;";
$indexArray[] = array('user_settings', 'timestamp');
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;';
@ -1514,6 +1532,17 @@ class AppModel extends Model
return ucfirst($field) . ' cannot be empty.';
}
public function valueIsJson($value)
{
$field = array_keys($value);
$field = $field[0];
$json_decoded = json_decode($value[$field]);
if ($json_decoded === null) {
return __('Invalid JSON.');
}
return true;
}
public function valueIsID($value)
{
$field = array_keys($value);
@ -1766,44 +1795,47 @@ class AppModel extends Model
return $updates;
}
public function populateNotifications($user)
public function populateNotifications($user, $mode = 'full')
{
$notifications = array();
$proposalCount = $this->_getProposalCount($user);
$notifications['total'] = 0;
$notifications['proposalCount'] = $proposalCount[0];
$notifications['total'] += $proposalCount[0];
$notifications['proposalEventCount'] = $proposalCount[1];
list($notifications['proposalCount'], $notifications['proposalEventCount']) = $this->_getProposalCount($user, $mode);
$notifications['total'] = $notifications['proposalCount'];
if (Configure::read('MISP.delegation')) {
$delegationCount = $this->_getDelegationCount($user);
$notifications['total'] += $delegationCount;
$notifications['delegationCount'] = $delegationCount;
$notifications['delegationCount'] = $this->_getDelegationCount($user);
$notifications['total'] += $notifications['delegationCount'];
}
return $notifications;
}
private function _getProposalCount($user)
// 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');
$this->ShadowAttribute->recursive = -1;
$shadowAttributes = $this->ShadowAttribute->find('all', array(
$results[0] = $this->ShadowAttribute->find(
'count',
array(
'recursive' => -1,
'fields' => array('event_id', 'event_org_id'),
'conditions' => array(
'ShadowAttribute.event_org_id' => $user['org_id'],
'ShadowAttribute.deleted' => 0,
)));
$results = array();
$eventIds = array();
$results[0] = count($shadowAttributes);
foreach ($shadowAttributes as $sa) {
if (!in_array($sa['ShadowAttribute']['event_id'], $eventIds)) {
$eventIds[] = $sa['ShadowAttribute']['event_id'];
}
)
)
);
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];
}
$results[1] = count($eventIds);
return $results;
}
@ -1811,10 +1843,8 @@ class AppModel extends Model
{
$this->EventDelegation = ClassRegistry::init('EventDelegation');
$delegations = $this->EventDelegation->find('count', array(
'recursive' => -1,
'conditions' => array(
'EventDelegation.org_id' => $user['org_id']
)
'recursive' => -1,
'conditions' => array('EventDelegation.org_id' => $user['org_id'])
));
return $delegations;
}
@ -2387,4 +2417,21 @@ class AppModel extends Model
}
}
}
/**
* @param string $message
* @param Exception $exception
* @param int $type
* @return bool
*/
protected function logException($message, Exception $exception, $type = LOG_ERR)
{
$message = sprintf("%s\n[%s] %s",
$message,
get_class($exception),
$exception->getMessage()
);
$message .= "\nStack Trace:\n" . $exception->getTraceAsString();
return $this->log($message, $type);
}
}

View File

@ -126,7 +126,7 @@ class Attribute extends AppModel
'Financial fraud' => array(
'desc' => __('Financial Fraud indicators'),
'formdesc' => __('Financial Fraud indicators, for example: IBAN Numbers, BIC codes, Credit card numbers, etc.'),
'types' => array('btc', 'xmr', 'iban', 'bic', 'bank-account-nr', 'aba-rtn', 'bin', 'cc-number', 'prtn', 'phone-number', 'comment', 'text', 'other', 'hex', 'anonymised'),
'types' => array('btc', 'dash', 'xmr', 'iban', 'bic', 'bank-account-nr', 'aba-rtn', 'bin', 'cc-number', 'prtn', 'phone-number', 'comment', 'text', 'other', 'hex', 'anonymised'),
),
'Support Tool' => array(
'desc' => __('Tools supporting analysis or detection of the event'),
@ -211,6 +211,7 @@ class Attribute extends AppModel
'target-location' => array('desc' => __('Attack Targets Physical Location(s)'), 'default_category' => 'Targeting data', 'to_ids' => 0),
'target-external' => array('desc' => __('External Target Organizations Affected by this Attack'), 'default_category' => 'Targeting data', 'to_ids' => 0),
'btc' => array('desc' => __('Bitcoin Address'), 'default_category' => 'Financial fraud', 'to_ids' => 1),
'dash' => array('desc' => __('Dash Address'), 'default_category' => 'Financial fraud', 'to_ids' => 1),
'xmr' => array('desc' => __('Monero Address'), 'default_category' => 'Financial fraud', 'to_ids' => 1),
'iban' => array('desc' => __('International Bank Account Number'), 'default_category' => 'Financial fraud', 'to_ids' => 1),
'bic' => array('desc' => __('Bank Identifier Code Number also known as SWIFT-BIC, SWIFT code or ISO 9362 code'), 'default_category' => 'Financial fraud', 'to_ids' => 1),
@ -606,6 +607,14 @@ class Attribute extends AppModel
public function beforeSave($options = array())
{
if (!empty($this->data['Attribute']['id'])) {
$this->old = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Attribute.id' => $this->data['Attribute']['id'])
));
} else {
$this->old = false;
}
// explode value of composite type in value1 and value2
// or copy value to value1 if not composite type
if (!empty($this->data['Attribute']['type'])) {
@ -623,11 +632,6 @@ class Attribute extends AppModel
$this->data['Attribute']['value2'] = '';
}
}
// update correlation... (only needed here if there's an update)
if ($this->id || !empty($this->data['Attribute']['id'])) {
$this->__beforeSaveCorrelation($this->data['Attribute']);
}
// always return true after a beforeSave()
return true;
}
@ -670,7 +674,26 @@ class Attribute extends AppModel
$this->__alterAttributeCount($this->data['Attribute']['event_id'], false, $passedEvent);
}
} else {
$this->__afterSaveCorrelation($this->data['Attribute'], false, $passedEvent);
/*
* Only recorrelate if:
* - We are dealing with a new attribute OR
* - The existing attribute's previous state is known AND
* value, type or disable correlation have changed
* This will avoid recorrelations when it's not really needed, such as adding a tag
*/
if (!$created) {
if (
empty($this->old) ||
$this->data['Attribute']['value'] != $this->old['Attribute']['value'] ||
$this->data['Attribute']['disable_correlation'] != $this->old['Attribute']['disable_correlation'] ||
$this->data['Attribute']['type'] != $this->old['Attribute']['type']
) {
$this->__beforeSaveCorrelation($this->data['Attribute']);
$this->__afterSaveCorrelation($this->data['Attribute'], false, $passedEvent);
}
} else {
$this->__afterSaveCorrelation($this->data['Attribute'], false, $passedEvent);
}
}
$result = true;
// if the 'data' field is set on the $this->data then save the data to the correct file
@ -799,7 +822,6 @@ class Attribute extends AppModel
$this->complexTypeTool = new ComplexTypeTool();
$this->data['Attribute']['value'] = $this->complexTypeTool->refangValue($this->data['Attribute']['value'], $this->data['Attribute']['type']);
if (!empty($this->data['Attribute']['object_id']) && empty($this->data['Attribute']['object_relation'])) {
return false;
}
@ -1351,6 +1373,7 @@ class Attribute extends AppModel
case 'iban':
case 'bic':
case 'btc':
case 'dash':
case 'xmr':
if (preg_match('/^[a-zA-Z0-9]+$/', $value)) {
$returnValue = true;
@ -3103,7 +3126,10 @@ class Attribute extends AppModel
if (!empty($options['includeGalaxy'])) {
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
}
if (Configure::read('MISP.proposals_block_attributes') && isset($options['conditions']['AND']['Attribute.to_ids']) && $options['conditions']['AND']['Attribute.to_ids'] == 1) {
if (
Configure::read('MISP.proposals_block_attributes') &&
!empty($options['allow_proposal_blocking'])
) {
$this->bindModel(array('hasMany' => array('ShadowAttribute' => array('foreignKey' => 'old_id'))));
$proposalRestriction = array(
'ShadowAttribute' => array(
@ -4236,6 +4262,7 @@ class Attribute extends AppModel
if (!isset($filters['published'])) {
$filters['published'] = 1;
}
$filters['allow_proposal_blocking'] = 1;
}
if (!empty($filters['quickFilter'])) {
$filters['searchall'] = $filters['quickFilter'];
@ -4270,7 +4297,8 @@ class Attribute extends AppModel
'includeSightings' => !empty($filters['includeSightings']) ? $filters['includeSightings'] : 0,
'includeCorrelations' => !empty($filters['includeCorrelations']) ? $filters['includeCorrelations'] : 0,
'includeDecayScore' => !empty($filters['includeDecayScore']) ? $filters['includeDecayScore'] : 0,
'includeFullModel' => !empty($filters['includeFullModel']) ? $filters['includeFullModel'] : 0
'includeFullModel' => !empty($filters['includeFullModel']) ? $filters['includeFullModel'] : 0,
'allow_proposal_blocking' => !empty($filters['allow_proposal_blocking']) ? $filters['allow_proposal_blocking'] : 0
);
if (!empty($filters['attackGalaxy'])) {
$params['attackGalaxy'] = $filters['attackGalaxy'];

View File

@ -2211,7 +2211,10 @@ class Event extends AppModel
}
}
}
if (Configure::read('MISP.proposals_block_attributes') && isset($options['to_ids']) && $options['to_ids']) {
if (
Configure::read('MISP.proposals_block_attributes') &&
!empty($options['allow_proposal_blocking'])
) {
foreach ($results[$eventKey]['Attribute'][$key]['ShadowAttribute'] as $sa) {
if ($sa['proposal_to_delete'] || $sa['to_ids'] == 0) {
unset($results[$eventKey]['Attribute'][$key]);
@ -2980,10 +2983,13 @@ class Event extends AppModel
$sgModel = ClassRegistry::init('SharingGroup');
$userCount = count($users);
$this->UserSetting = ClassRegistry::init('UserSetting');
foreach ($users as $k => $user) {
$body = $this->__buildAlertEmailBody($event[0], $user, $oldpublish, $sgModel);
$bodyNoEnc = "A new or modified event was just published on " . $this->__getAnnounceBaseurl() . "/events/view/" . $event[0]['Event']['id'];
$this->User->sendEmail(array('User' => $user), $body, $bodyNoEnc, $subject);
if ($this->UserSetting->checkPublishFilter($user, $event[0])) {
$body = $this->__buildAlertEmailBody($event[0], $user, $oldpublish, $sgModel);
$bodyNoEnc = "A new or modified event was just published on " . $this->__getAnnounceBaseurl() . "/events/view/" . $event[0]['Event']['id'];
$this->User->sendEmail(array('User' => $user), $body, $bodyNoEnc, $subject);
}
if ($processId) {
$this->Job->id = $processId;
$this->Job->saveField('progress', $k / $userCount * 100);
@ -4168,9 +4174,10 @@ class Event extends AppModel
// Performs all the actions required to publish an event
public function publish($id, $passAlong = null, $jobId = null)
{
$this->id = $id;
$this->recursive = 0;
$event = $this->read(null, $id);
$event = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Event.id' => $id)
));
if (empty($event)) {
return false;
}
@ -6709,6 +6716,7 @@ class Event extends AppModel
if (!isset($filters['published'])) {
$filters['published'] = 1;
}
$filters['allow_proposal_blocking'] = 1;
}
if (!empty($exportTool->renderView)) {

View File

@ -422,7 +422,7 @@ class Feed extends AppModel
}
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not add event '$uuid' from feed {$feed['Feed']['id']}.", $e));
$this->logException("Could not add event '$uuid' from feed {$feed['Feed']['id']}.", $e);
$results['add']['fail'] = array('uuid' => $uuid, 'reason' => $e->getMessage());
}
@ -439,7 +439,7 @@ class Feed extends AppModel
$results['edit']['success'] = $uuid;
}
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not edit event '$uuid' from feed {$feed['Feed']['id']}.", $e));
$this->logException("Could not edit event '$uuid' from feed {$feed['Feed']['id']}.", $e);
$results['edit']['fail'] = array('uuid' => $uuid, 'reason' => $e->getMessage());
}
@ -780,7 +780,7 @@ class Feed extends AppModel
try {
$actions = $this->getNewEventUuids($this->data, $HttpSocket);
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not get new event uuids for feed $feedId.", $e));
$this->logException("Could not get new event uuids for feed $feedId.", $e);
$this->jobProgress($jobId, 'Could not fetch event manifest. See log for more details.');
return false;
}
@ -798,7 +798,7 @@ class Feed extends AppModel
try {
$temp = $this->getFreetextFeed($this->data, $HttpSocket, $this->data['Feed']['source_format'], 'all');
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not get freetext feed $feedId", $e));
$this->logException("Could not get freetext feed $feedId", $e);
$this->jobProgress($jobId, 'Could not fetch freetext feed. See log for more details.');
return false;
}
@ -821,7 +821,7 @@ class Feed extends AppModel
try {
$result = $this->saveFreetextFeedData($this->data, $data, $user);
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not save freetext feed data for feed $feedId.", $e));
$this->logException("Could not save freetext feed data for feed $feedId.", $e);
return false;
}
@ -1037,14 +1037,15 @@ class Feed extends AppModel
try {
$values = $this->getFreetextFeed($feed, $HttpSocket, $feed['Feed']['source_format'], 'all');
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not get freetext feed $feedId", $e));
$this->logException("Could not get freetext feed $feedId", $e);
$this->jobProgress($jobId, 'Could not fetch freetext feed. See log for more details.');
return false;
}
foreach ($values as $k => $value) {
$redis->sAdd('misp:feed_cache:' . $feedId, md5($value['value']));
$redis->sAdd('misp:feed_cache:combined', md5($value['value']));
$md5Value = md5($value['value']);
$redis->sAdd('misp:feed_cache:' . $feedId, $md5Value);
$redis->sAdd('misp:feed_cache:combined', $md5Value);
if ($k % 1000 == 0) {
$this->jobProgress($jobId, "Feed $feedId: $k/" . count($values) . " values cached.");
}
@ -1060,7 +1061,7 @@ class Feed extends AppModel
try {
$manifest = $this->getManifest($feed, $HttpSocket);
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not get manifest for feed $feedId.", $e));
$this->logException("Could not get manifest for feed $feedId.", $e);
return false;
}
@ -1071,7 +1072,7 @@ class Feed extends AppModel
try {
$event = $this->downloadAndParseEventFromFeed($feed, $uuid, $HttpSocket);
} catch (Exception $e) {
CakeLog::error($this->exceptionAsMessage("Could not get and parse event '$uuid' for feed $feedId.", $e));
$this->logException("Could not get and parse event '$uuid' for feed $feedId.", $e);
return false;
}
@ -1112,7 +1113,7 @@ class Feed extends AppModel
try {
$cache = $this->getCache($feed, $HttpSocket);
} catch (Exception $e) {
CakeLog::notice($this->exceptionAsMessage("Could not get cache file for $feedId.", $e));
$this->logException("Could not get cache file for $feedId.", $e, LOG_NOTICE);
return false;
}
@ -1230,8 +1231,10 @@ class Feed extends AppModel
public function importFeeds($feeds, $user, $default = false)
{
$feeds = json_decode($feeds, true);
if (!isset($feeds[0])) {
if (is_string($feeds)) {
$feeds = json_decode($feeds, true);
}
if ($feeds && !isset($feeds[0])) {
$feeds = array($feeds);
}
$results = array('successes' => 0, 'fails' => 0);
@ -1625,22 +1628,6 @@ class Feed extends AppModel
}
}
/**
* @param string $message
* @param Exception $exception
* @return string
*/
private function exceptionAsMessage($message, $exception)
{
$message = sprintf("%s\n[%s] %s",
$message,
get_class($exception),
$exception->getMessage()
);
$message .= "\nStack Trace:\n" . $exception->getTraceAsString();
return $message;
}
/**
* remove all events tied to a feed. Returns int on success, error message
* as string on failure

View File

@ -217,6 +217,16 @@ class Server extends AppModel
'type' => 'string',
'cli_only' => 1
),
'ca_path' => array(
'level' => 1,
'description' => __('MISP will default to the bundled mozilla certificate bundle shipped with the framework, which is rather stale. If you wish to use an alternate bundle, just set this setting using the path to the bundle to use. This setting can only be modified via the CLI.'),
'value' => APP . 'Lib/cakephp/lib/Cake/Config/cacert.pem',
'errorMessage' => '',
'null' => true,
'test' => 'testForCABundle',
'type' => 'string',
'cli_only' => 1
),
'disable_auto_logout' => array(
'level' => 1,
'description' => __('In some cases, a heavily used MISP instance can generate unwanted blackhole errors due to a high number of requests hitting the server. Disable the auto logout functionality to ease the burden on the system.'),
@ -3381,6 +3391,17 @@ class Server extends AppModel
return $this->__testForFile($value, APP . 'files' . DS . 'terms');
}
public function testForCABundle($value)
{
$file = new File($value);
if (!$file->exists()) {
return __('Invalid file path or file not accessible.');
}
if ($file->ext() !== 'pem') {
return __('File has to be in .pem format.');
}
}
public function testForStyleFile($value)
{
if (empty($value)) {
@ -5205,7 +5226,6 @@ class Server extends AppModel
'page' => $i,
'limit' => $chunk_size
);
debug($filter_rules);
$request = $this->setupSyncRequest($server);
try {
$response = $HttpSocket->post($server['Server']['url'] . '/attributes/restSearch.json', json_encode($filter_rules), $request);

View File

@ -10,6 +10,8 @@ class ShadowAttribute extends AppModel
public $name = 'ShadowAttribute'; // TODO general
public $recursive = -1;
public $actsAs = array(
'SysLogLogable.SysLogLogable' => array( // TODO Audit, logable
'userModel' => 'User',
@ -508,7 +510,12 @@ class ShadowAttribute extends AppModel
public function getEventContributors($id)
{
$orgs = $this->find('all', array('fields' => array('DISTINCT(org_id)'), 'conditions' => array('event_id' => $id), 'order' => false));
$orgs = $this->find('all', array('fields' => array(
'DISTINCT(ShadowAttribute.org_id)'),
'conditions' => array('event_id' => $id),
'recursive' => -1,
'order' => false
));
$org_ids = array();
$this->Organisation = ClassRegistry::init('Organisation');
foreach ($orgs as $org) {

View File

@ -162,7 +162,6 @@ class TagCollection extends AppModel
if (!empty($collection['Galaxy'])) {
foreach ($collection['Galaxy'] as $galaxy) {
foreach ($galaxy['GalaxyCluster'] as $cluster) {
debug($galaxy);
$tag_id = $this->TagCollectionTag->Tag->lookupTagIdFromName($cluster['tag_name']);
if ($tag_id === -1) {
$tag = array(

View File

@ -38,21 +38,24 @@ class Taxonomy extends AppModel
public function update()
{
$directories = glob(APP . 'files' . DS . 'taxonomies' . DS . '*', GLOB_ONLYDIR);
foreach ($directories as $k => $dir) {
$dir = str_replace(APP . 'files' . DS . 'taxonomies' . DS, '', $dir);
if ($dir === 'tools') {
unset($directories[$k]);
} else {
$directories[$k] = $dir;
}
}
$updated = array();
foreach ($directories as $dir) {
if (!file_exists(APP . 'files' . DS . 'taxonomies' . DS . $dir . DS . 'machinetag.json')) {
$dir = basename($dir);
if ($dir === 'tools') {
continue;
}
$file = new File(APP . 'files' . DS . 'taxonomies' . DS . $dir . DS . 'machinetag.json');
if (!$file->exists()) {
continue;
}
$vocab = json_decode($file->read(), true);
$file->close();
if ($vocab === null) {
$updated['fails'][] = array('namespace' => $dir, 'fail' => "File machinetag.json is not valid JSON.");
continue;
}
if (isset($vocab['type'])) {
if (is_array($vocab['type'])) {
if (!in_array('event', $vocab['type'])) {
@ -64,7 +67,7 @@ class Taxonomy extends AppModel
}
}
}
$file->close();
if (!isset($vocab['version'])) {
$vocab['version'] = 1;
}

View File

@ -202,7 +202,8 @@ class User extends AppModel
'finderQuery' => '',
'counterQuery' => ''
),
'Post'
'Post',
'UserSetting'
);
public $actsAs = array(
@ -605,7 +606,7 @@ class User extends AppModel
public function getAuthUser($id)
{
if (empty($id)) {
throw new Exception('Invalid user ID.');
throw new NotFoundException('Invalid user ID.');
}
$conditions = array('User.id' => $id);
$user = $this->find('first', array('conditions' => $conditions, 'recursive' => -1,'contain' => array('Organisation', 'Role', 'Server')));

251
app/Model/UserSetting.php Normal file
View File

@ -0,0 +1,251 @@
<?php
App::uses('AppModel', 'Model');
class UserSetting extends AppModel
{
public $useTable = 'user_settings';
public $recursive = -1;
public $actsAs = array(
'SysLogLogable.SysLogLogable' => array(
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'full'),
'Containable',
);
public $validate = array(
'json' => array(
'isValidJson' => array(
'rule' => array('isValidJson'),
)
)
);
public $belongsTo = array(
'User'
);
public $validSettings = array(
'publish_alert_filter' => array(
'placeholder' => array(
'AND' => array(
'NOT' => array(
'EventTag.name' => array(
'%osint%'
)
),
'OR' => array(
'Tag.name' => array(
'tlp:green',
'tlp:amber',
'tlp:red',
'%privint%'
)
)
)
)
)
);
// 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();
}
if (!empty($this->data['UserSetting']['value']) && $this->data['UserSetting']['value'] !== 'null') {
if (is_array($this->data['UserSetting']['value'])) {
$this->data['UserSetting']['value'] = json_encode($this->data['UserSetting']['value']);
}
} else {
$this->data['UserSetting']['value'] = '[]';
}
return true;
}
// Once we run a find, let us decode the JSON field so we can interact with the contents as if it was an array
public function afterFind($results, $primary = false)
{
foreach ($results as $k => $v) {
$results[$k]['UserSetting']['value'] = json_decode($v['UserSetting']['value'], true);
}
return $results;
}
public function checkSettingValidity($setting)
{
return isset($this->validSettings[$setting]);
}
/*
* canModify expects an auth user object or a user ID and a loaded setting as input parameters
* check if the user can modify/remove the given entry
* returns true for site admins
* returns true for org admins if setting["User"]["org_id"] === $user["org_id"]
* returns true for any user if setting["user_id"] === $user["id"]
*/
public function checkAccess($user, $setting, $user_id = false)
{
if (is_numeric($user)) {
$user = $this->User->getAuthUser($user);
}
if (empty($setting) && !empty($user_id) && is_numeric($user_id)) {
$userToCheck = $this->User->find('first', array(
'conditions' => array('User.id' => $user_id),
'recursive' => -1
));
if (empty($userToCheck)) {
return false;
}
$setting = array(
'User' => array(
'org_id' => $userToCheck['User']['org_id']
),
'UserSetting' => array(
'user_id' => $userToCheck['User']['id']
)
);
}
if ($user['Role']['perm_site_admin']) {
return true;
} else if ($user['Role']['perm_admin']) {
if ($user['org_id'] === $setting['User']['org_id']) {
return true;
}
} else {
if (
$user['id'] === $setting['UserSetting']['user_id'] &&
(!Configure::check('MISP.disableUserSelfManagement') || Configure::check('MISP.disableUserSelfManagement'))
) {
return true;
}
}
return false;
}
/*
* Check whether the event is something the user is interested (to be alerted on)
*
*/
public function checkPublishFilter($user, $event)
{
$rule = $this->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.user_id' => $user['id'],
'UserSetting.setting' => 'publish_alert_filter'
)
));
// We should return true if no setting has been configured, or there's a setting with an empty value
if (empty($rule) || empty($rule['UserSetting']['value'])) {
return true;
}
// recursively evaluate the boolean tree to true/false and return the value
$result = $this->__recursiveConvert($rule['UserSetting']['value'], $event);
if (isset($result[0])) {
return $result[0];
} else {
return false;
}
}
/*
* Convert a complex rule set recursively
* takes as params a rule branch and an event to check against
* evaluate whether the rule set evaluates as true/false
* The full evaluation involves resolving the boolean branches
* valid boolean operators are OR, AND, NOT all capitalised as strings
*/
private function __recursiveConvert($rule, $event)
{
$toReturn = array();
if (is_array($rule)) {
foreach ($rule as $k => $v) {
if (in_array($k, array('OR', 'NOT', 'AND'))) {
$parts = $this->__recursiveConvert($v, $event);
$temp = null;
foreach ($parts as $partValue) {
if ($temp === null) {
$temp = ($k === 'NOT') ? !$partValue : $partValue;
} else {
if ($k === 'OR') {
$temp = $temp || $partValue;
} elseif ($k === 'AND') {
$temp = $temp && $partValue;
} else {
$temp = $temp && !$partValue;
}
}
}
$toReturn []= $temp;
} else {
$toReturn []= $this->__checkEvent($k, $v, $event);
}
}
return $toReturn;
} else {
return false;
}
}
/*
* Checks if an event matches the given rule
* valid filters:
* - AttributeTag.name
* - EventTag.name
* - Tag.name (checks against both event and attribute tags)
* - Orgc.uuid
* - Orgc.name
* Values passed can be used for direct string comparisons or alternatively
* as substring matches by encapsulating the string in a pair of "%" characters
* Each rule can take a list of values
*/
private function __checkEvent($rule, $lookup_values, $event)
{
if (!is_array($lookup_values)) {
$lookup_values = array($lookup_values);
}
foreach ($lookup_values as $k => $v) {
$lookup_values[$k] = mb_strtolower($v);
}
if ($rule === 'AttributeTag.name') {
$values = array_merge(
Hash::extract($event, 'Attribute.{n}.AttributeTag.{n}.Tag.name'),
Hash::extract($event, 'Object.{n}.Attribute.{n}.AttributeTag.{n}.Tag.name')
);
} else if ($rule === 'EventTag.name') {
$values = Hash::extract($event, 'EventTag.{n}.Tag.name');
} else if ($rule === 'Orgc.name') {
$values = array($event['Event']['Orgc']['name']);
} else if ($rule === 'Orgc.uuid') {
$values = array($event['Event']['Orgc']['uuid']);
} else if ($rule === 'Tag.name') {
$values = array_merge(
Hash::extract($event, 'Attribute.{n}.AttributeTag.{n}.Tag.name'),
Hash::extract($event, 'Object.{n}.Attribute.{n}.AttributeTag.{n}.Tag.name'),
Hash::extract($event, 'EventTag.{n}.Tag.name')
);
}
if (!empty($values)) {
foreach ($values as $extracted_value) {
$extracted_value = mb_strtolower($extracted_value);
foreach ($lookup_values as $lookup_value) {
$lookup_value_trimmed = trim($lookup_value, "%");
if (strlen($lookup_value_trimmed) != strlen($lookup_value)) {
if (strpos($extracted_value, $lookup_value_trimmed) !== false) {
return true;
}
} else {
if ($extracted_value === $lookup_value) {
return true;
}
}
}
}
}
return false;
}
}

View File

@ -18,9 +18,7 @@
if (isset($action['postLink'])) {
echo $this->Form->postLink(
'',
array(
'url' => $url
),
$url,
array(
'class' => $this->FontAwesome->getClass($action['icon']) . ' black ' . (empty($action['class']) ? '' : h($action['class'])),
'title' => empty($action['title']) ? '' : h($action['title']),

View File

@ -1,7 +1,12 @@
<?php
$data = h(Hash::extract($row, $field['data_path']));
echo sprintf(
'<div style="white-space:pre;" class="blue bold">%s</div>',
json_encode($data, JSON_PRETTY_PRINT)
'<div class="json_container_%s"></div>',
h($k)
);
?>
<script type="text/javascript">
$(document).ready(function() {
$('.json_container_<?php echo h($k);?>').html(syntaxHighlightJson(<?php echo json_encode($data); ?>, 4));
});
</script>

View File

@ -446,6 +446,16 @@
'url' => '/users/view/me',
'text' => __('My Profile')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'user_settings_index_me',
'url' => '/user_settings/index/user_id:me',
'text' => __('My Settings')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'user_settings_set',
'url' => '/user_settings/setSetting',
'text' => __('Set Setting')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => '/users/dashboard',
'text' => __('Dashboard')
@ -668,6 +678,16 @@
));
}
if ($isAdmin) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'user_settings_index',
'url' => '/user_settings/index/user_id:all',
'text' => __('User settings')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'user_settings_set',
'url' => '/user_settings/setSetting',
'text' => __('Set Setting')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'contact',
'url' => '/admin/users/email',
@ -913,7 +933,6 @@
}
}
break;
case 'decayingModel':
if ($isAdmin) {
if ($isSiteAdmin && ($menuItem === 'view' || $menuItem === 'index')) {

View File

@ -147,6 +147,14 @@
'text' => __('My Profile'),
'url' => '/users/view/me'
),
array(
'text' => __('My Settings'),
'url' => '/user_settings/index/user_id:me'
),
array(
'text' => __('Set Setting'),
'url' => '/user_settings/setSetting'
),
array(
'text' => __('Dashboard'),
'url' => '/users/dashboard'
@ -270,6 +278,14 @@
'text' => __('List Users'),
'url' => '/admin/users/index'
),
array(
'text' => __('List User Settings'),
'url' => '/user_settings/index/user_id:all'
),
array(
'text' => __('Set User Setting'),
'url' => '/user_settings/setSetting'
),
array(
'text' => __('Add User'),
'url' => '/admin/users/add'

View File

@ -0,0 +1,3 @@
<?php
echo h(Hash::extract($row, $field['data_path'])[0]);
?>

View File

@ -0,0 +1,103 @@
<?php
/*
* echo $this->element('/genericElements/IndexTable/index_table', array(
* 'top_bar' => (
* // search/filter bar information compliant with ListTopBar
* ),
* 'data' => array(
// the actual data to be used
* ),
* 'fields' => array(
* // field list with information for the paginator
* ),
* 'title' => optional title,
* 'description' => optional description
* ));
*
*/
echo '<div class="index">';
echo $this->element('/genericElements/IndexTable/index_table', array(
'data' => array(
'data' => $data,
'top_bar' => array(
'children' => array(
array(
'type' => 'simple',
'children' => array(
array(
'active' => $context === 'me',
'url' => $baseurl . '/user_settings/index/user_id:me',
'text' => __('Me'),
),
array(
'active' => $context === 'org',
'url' => $baseurl . '/user_settings/index/user_id:org',
'text' => __('Organisation'),
'requirement' => $isAdmin
),
array(
'active' => $context === 'all',
'url' => $baseurl . '/user_settings/index/user_id:all',
'text' => __('All'),
'requirement' => $isSiteAdmin
)
)
)
)
),
'fields' => array(
array(
'name' => __('Id'),
'sort' => 'id',
'class' => 'short',
'data_path' => 'UserSetting.id'
),
array(
'name' => __('User'),
'sort' => 'User.email',
'class' => 'short',
'data_path' => 'User.email'
),
array(
'name' => __('Setting'),
'class' => 'short',
'sort' => 'type',
'data_path' => 'UserSetting.setting'
),
array(
'name' => __('Value'),
'sort' => 'type',
'element' => 'json',
'data_path' => 'UserSetting.value'
)
),
'title' => __('User settings management'),
'description' => __('Manage the individual user settings.'),
'actions' => array(
array(
'url' => '/user_settings/setSetting',
'url_params_data_paths' => array(
'UserSetting.user_id',
'UserSetting.setting'
),
'icon' => 'edit'
),
array(
'url' => '/user_settings/delete',
'url_params_data_paths' => array(
'UserSetting.id'
),
'icon' => 'trash',
'postLink' => true,
'postLinkConfirm' => __('Are you sure you wish to delete this entry?')
)
)
)
));
echo '</div>';
if ($context === 'me' || (!$isAdmin && !$isSiteAdmin)) {
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'user_settings_index_me'));
} else {
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'admin', 'menuItem' => 'user_settings_index'));
}
?>

View File

@ -0,0 +1,77 @@
<?php
echo sprintf(
'<div class="usersetting form">%s<fieldset><legend>%s</legend>%s</fieldset>%s%s</div>',
$this->Form->create('UserSetting'),
__('Set User Setting'),
sprintf(
'%s%s%s',
$this->Form->input(
'user_id',
array(
'div' => 'clear',
'class' => 'input input-xxlarge',
'options' => array($users),
'disabled' => count($users) === 1
)
),
$this->Form->input(
'setting',
array(
'div' => 'clear',
'class' => 'input input-xxlarge',
'options' => array_combine(array_keys($validSettings), array_keys($validSettings))
)
),
$this->Form->input(
'value',
array(
'div' => 'clear',
'class' => 'input input-xxlarge',
'type' => 'textarea',
)
)
),
$this->Form->button(__('Submit'), array('class' => 'btn btn-primary')),
$this->Form->end()
);
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'globalActions', 'menuItem' => 'user_settings_set'));
?>
<script type="text/javascript">
var validSettings = <?php echo json_encode($validSettings); ?>;
$(document).ready(function() {
loadUserSettingValue();
changeUserSettingPlaceholder();
$('#UserSettingSetting').on('change', function() {
loadUserSettingValue();
changeUserSettingPlaceholder();
});
$('#UserSettingUserId').on('change', function() {
loadUserSettingValue();
changeUserSettingPlaceholder();
});
});
function loadUserSettingValue() {
var user_id = $('#UserSettingUserId').val();
var setting = $('#UserSettingSetting').val();
$.ajax({
type:"get",
url: baseurl + "/user_settings/getSetting/" + user_id + "/" + setting,
success: function (data, textStatus) {
if (data === '[]') {
var data = '';
} else {
data = JSON.parse(data);
data = JSON.stringify(data, undefined, 4);
}
$('#UserSettingValue').val(data);
}
});
}
function changeUserSettingPlaceholder() {
var setting = $('#UserSettingSetting').val();
if (setting in validSettings) {
$('#UserSettingValue').attr("placeholder", "Example:\n" + JSON.stringify(validSettings[setting]["placeholder"], undefined, 4));
}
}
</script>

View File

View File

@ -1202,10 +1202,15 @@ function submitPopoverForm(context_id, referer, update_context_id) {
$('#sightingsListAllToggle').addClass('btn-primary');
}
if (context == 'event' && (referer == 'add' || referer == 'massEdit' || referer == 'replaceAttributes' || referer == 'addObjectReference')) eventUnpublish();
},
error: function (jqXHR, textStatus, errorThrown) {
showMessage('fail', textStatus + ": " + errorThrown);
},
complete: function () {
$(".loading").hide();
},
type:"post",
url:url
type: "post",
url: url,
});
}
@ -4285,7 +4290,7 @@ function syntaxHighlightJson(json, indent) {
if (typeof json == 'string') {
json = JSON.parse(json);
}
json = JSON.stringify(json, undefined, 2);
json = JSON.stringify(json, undefined, indent);
json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/(?:\r\n|\r|\n)/g, '<br>').replace(/ /g, '&nbsp;');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
var cls = 'json_number';

View File

@ -79,6 +79,13 @@ def make_matrix_content(pos, max_cols):
return out
def jq_file(fname):
p1 = subprocess.Popen(['jq', '.', fname], stdout=subprocess.PIPE)
output = p1.stdout.read()
with open(fname, 'wb') as f:
f.write(output)
# verify if the folders exist before continuing
folders = ['PyMISP', 'misp-book', 'misp-website', 'misp-rfc']
for folder in folders:
@ -232,6 +239,7 @@ describe_types = order_dict(describe_types)
with open('../../PyMISP/pymisp/data/describeTypes.json', 'w') as f:
json.dump(describe_types, f, sort_keys=True, indent=2)
f.write('\n')
jq_file('../../PyMISP/pymisp/data/describeTypes.json')
# misp-objects
@ -246,6 +254,7 @@ schema_objects['defs']['attribute']['properties']['categories']['items']['enum']
with open('../../misp-objects/schema_objects.json', 'w') as f:
json.dump(schema_objects, f, sort_keys=True, indent=2)
f.write('\n')
jq_file('../../misp-objects/schema_objects.json')
# print(types)
# print(categories)