mirror of https://github.com/MISP/MISP
Merge branch 'dev_session' into 2.4
commit
480e3b2969
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2599,6 +2599,7 @@ class EventsController extends AppController
|
|||
}
|
||||
// send out the email
|
||||
$emailResult = $this->Event->sendAlertEmailRouter($id, $this->Auth->user(), $this->Event->data['Event']['publish_timestamp']);
|
||||
throw new Exception();
|
||||
if (is_bool($emailResult) && $emailResult == true) {
|
||||
// Performs all the actions required to publish an event
|
||||
$result = $this->Event->publishRouter($id, null, $this->Auth->user());
|
||||
|
|
|
@ -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.'));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
|
||||
public $advanced_updates_description = array(
|
||||
|
@ -1246,6 +1247,19 @@ 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 '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 +1528,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);
|
||||
|
|
|
@ -799,7 +799,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;
|
||||
}
|
||||
|
|
|
@ -2980,10 +2980,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);
|
||||
|
|
|
@ -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')));
|
||||
|
|
|
@ -0,0 +1,252 @@
|
|||
<?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'] = '[]';
|
||||
}
|
||||
debug($this->data);
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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']),
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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')) {
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<?php
|
||||
echo h(Hash::extract($row, $field['data_path'])[0]);
|
||||
?>
|
|
@ -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'));
|
||||
}
|
||||
?>
|
|
@ -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>
|
|
@ -4285,7 +4285,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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/(?:\r\n|\r|\n)/g, '<br>').replace(/ /g, ' ');
|
||||
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';
|
||||
|
|
Loading…
Reference in New Issue