mirror of https://github.com/MISP/MISP
Merge branch 'pentest_fixes' into develop
commit
63840c8b68
2
PyMISP
2
PyMISP
|
@ -1 +1 @@
|
|||
Subproject commit c5646d7463932f5c58b9569a7d771cdb8b2c048a
|
||||
Subproject commit b1892efb6a078d1370cee51c9103f3a591c628d2
|
|
@ -1 +1 @@
|
|||
{"major":2, "minor":4, "hotfix":156}
|
||||
{"major":2, "minor":4, "hotfix":157}
|
||||
|
|
|
@ -17,6 +17,7 @@ $config = array(
|
|||
'user_monitoring_enabled' => false,
|
||||
'authkey_keep_session' => false,
|
||||
'disable_local_feed_access' => false,
|
||||
'enable_svg_logos' => false,
|
||||
//'auth' => array('CertAuth.Certificate'), // additional authentication methods
|
||||
//'auth' => array('ShibbAuth.ApacheShibb'),
|
||||
//'auth' => array('AadAuth.AadAuthenticate'),
|
||||
|
|
|
@ -34,8 +34,8 @@ class AppController extends Controller
|
|||
|
||||
public $helpers = array('OrgImg', 'FontAwesome', 'UserName');
|
||||
|
||||
private $__queryVersion = '136';
|
||||
public $pyMispVersion = '2.4.155';
|
||||
private $__queryVersion = '139';
|
||||
public $pyMispVersion = '2.4.157';
|
||||
public $phpmin = '7.2';
|
||||
public $phprec = '7.4';
|
||||
public $phptoonew = '8.0';
|
||||
|
@ -1326,6 +1326,27 @@ class AppController extends Controller
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user can publish the given event.
|
||||
*
|
||||
* @param array $event
|
||||
* @return bool
|
||||
*/
|
||||
protected function __canPublishEvent(array $event)
|
||||
{
|
||||
if (!isset($event['Event'])) {
|
||||
throw new InvalidArgumentException('Passed object does not contain an Event.');
|
||||
}
|
||||
|
||||
if ($this->userRole['perm_site_admin']) {
|
||||
return true;
|
||||
}
|
||||
if ($this->userRole['perm_publish'] && $event['Event']['orgc_id'] == $this->Auth->user()['org_id']) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user can add or remove tags for given event.
|
||||
*
|
||||
|
|
|
@ -21,10 +21,40 @@ class AuthKeysController extends AppController
|
|||
public function index($id = false)
|
||||
{
|
||||
$conditions = $this->__prepareConditions();
|
||||
if ($id !== false) {
|
||||
$canCreateAuthkey = true;
|
||||
if ($id) {
|
||||
$this->set('user_id', $id);
|
||||
if ($this->_isAdmin()) {
|
||||
if ($this->_isSiteAdmin()) {
|
||||
$canCreateAuthkey = true;
|
||||
} else {
|
||||
$user = $this->AuthKey->User->find('first', [
|
||||
'recursive' => -1,
|
||||
'conditions' => [
|
||||
'User.id' => $id,
|
||||
'User.disabled' => false
|
||||
],
|
||||
'fields' => ['User.id', 'User.org_id', 'User.disabled'],
|
||||
'contain' => [
|
||||
'Role' => [
|
||||
'fields' => [
|
||||
'Role.perm_site_admin', 'Role.perm_admin'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
if ($user['Role']['perm_site_admin'] || ($user['Role']['perm_admin'] && $user['User']['id'] !== $this->Auth->user('id'))) {
|
||||
$canCreateAuthkey = false;
|
||||
} else {
|
||||
$canCreateAuthkey = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$canCreateAuthkey = (int)$id === (int)$this->Auth->user('id');
|
||||
}
|
||||
$conditions['AND'][] = ['AuthKey.user_id' => $id];
|
||||
}
|
||||
$this->set('canCreateAuthkey', $canCreateAuthkey);
|
||||
$keyUsageEnabled = Configure::read('MISP.log_user_ips') && Configure::read('MISP.log_user_ips_authkeys');
|
||||
$this->CRUD->index([
|
||||
'filters' => ['User.email', 'authkey_start', 'authkey_end', 'comment', 'User.id'],
|
||||
|
@ -123,8 +153,40 @@ class AuthKeysController extends AppController
|
|||
}
|
||||
$selectConditions = [];
|
||||
if (!$this->_isSiteAdmin()) {
|
||||
$selectConditions['AND'][] = ['User.id' => $this->Auth->user('id')];
|
||||
$params['override']['user_id'] = $this->Auth->user('id');
|
||||
if ($this->_isAdmin()) {
|
||||
$role_ids = $this->AuthKey->User->Role->find('column', [
|
||||
'fields' => ['Role.id'],
|
||||
'conditions' => [
|
||||
'AND' => [
|
||||
'Role.perm_site_admin' => false,
|
||||
'Role.perm_auth' => true,
|
||||
'Role.perm_admin' => false
|
||||
]
|
||||
]
|
||||
]);
|
||||
$user_ids = $this->AuthKey->User->find('column', [
|
||||
'fields' => ['User.id'],
|
||||
'conditions' => [
|
||||
'User.org_id' => $this->Auth->user('org_id'),
|
||||
'OR' => [
|
||||
'User.role_id' => $role_ids,
|
||||
'User.id' => $this->Auth->user('id')
|
||||
]
|
||||
]
|
||||
]);
|
||||
if (!empty($user_id)) {
|
||||
if (in_array($user_id, $user_ids)) {
|
||||
$user_ids = [$user_id];
|
||||
} else {
|
||||
throw new MethodNotAllowedException(__('Invalid user or insufficient privileges to create an authkey for the given user.'));
|
||||
}
|
||||
}
|
||||
$selectConditions['AND'][] = ['User.id' => $user_ids];
|
||||
$params['override']['user_id'] = $user_ids[0];
|
||||
} else {
|
||||
$selectConditions['AND'][] = ['User.id' => $this->Auth->user('id')];
|
||||
$params['override']['user_id'] = $this->Auth->user('id');
|
||||
}
|
||||
} else if ($user_id) {
|
||||
$selectConditions['AND'][] = ['User.id' => $user_id];
|
||||
$params['override']['user_id'] = $user_id;
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
<?php
|
||||
App::uses('AppController', 'Controller');
|
||||
|
||||
/**
|
||||
* @property CryptographicKey $CryptographicKey
|
||||
*/
|
||||
class CryptographicKeysController extends AppController
|
||||
{
|
||||
public $components = array('Session', 'RequestHandler');
|
||||
|
||||
public function beforeFilter()
|
||||
{
|
||||
parent::beforeFilter();
|
||||
}
|
||||
|
||||
public $paginate = array(
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999
|
||||
'limit' => 60,
|
||||
'maxLimit' => 9999
|
||||
);
|
||||
|
||||
public function add($type, $parent_id)
|
||||
|
@ -85,7 +83,8 @@ class CryptographicKeysController extends AppController
|
|||
{
|
||||
$key = $this->CryptographicKey->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => ['id', 'type', 'key_data', 'fingerprint']
|
||||
'fields' => ['id', 'type', 'key_data', 'fingerprint'],
|
||||
'conditions' => ['CryptographicKey.id' => $id]
|
||||
]);
|
||||
$this->set('id', $id);
|
||||
$this->set('title', __('Viewing %s key #%s', h($key['CryptographicKey']['type']), h($key['CryptographicKey']['id'])));
|
||||
|
|
|
@ -837,7 +837,11 @@ class EventsController extends AppController
|
|||
$events = $absolute_total === 0 ? [] : $this->Event->find('all', $rules);
|
||||
}
|
||||
$isCsvResponse = $this->response->type() === 'text/csv';
|
||||
$instanceFingerprint = $this->Event->CryptographicKey->ingestInstanceKey();
|
||||
try {
|
||||
$instanceFingerprint = $this->Event->CryptographicKey->ingestInstanceKey();
|
||||
} catch (Exception $e) {
|
||||
$instanceFingerprint = null;
|
||||
}
|
||||
if (!$minimal) {
|
||||
// Collect all tag IDs that are events
|
||||
$tagIds = [];
|
||||
|
@ -955,6 +959,9 @@ class EventsController extends AppController
|
|||
}
|
||||
foreach ($event['CryptographicKey'] as $cryptoKey) {
|
||||
if ($instanceFingerprint === $cryptoKey['fingerprint']) {
|
||||
$event['Event']['orgc_uuid'] = $event['Orgc']['uuid'];
|
||||
unset($event['Event']['protected']);
|
||||
$events[$key] = $event['Event'];
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
|
@ -1648,7 +1655,13 @@ class EventsController extends AppController
|
|||
$this->set('warnings', $this->Event->generateWarnings($event));
|
||||
$this->set('menuData', array('menuList' => 'event', 'menuItem' => 'viewEvent'));
|
||||
$this->set('mayModify', $this->__canModifyEvent($event));
|
||||
$this->set('instanceFingerprint', $this->Event->CryptographicKey->ingestInstanceKey());
|
||||
$this->set('mayPublish', $this->__canPublishEvent($event));
|
||||
try {
|
||||
$instanceKey = $this->Event->CryptographicKey->ingestInstanceKey();
|
||||
} catch (Exception $e) {
|
||||
$instanceKey = null;
|
||||
}
|
||||
$this->set('instanceFingerprint', $instanceKey);
|
||||
$this->__eventViewCommon($user);
|
||||
}
|
||||
|
||||
|
@ -3337,6 +3350,8 @@ class EventsController extends AppController
|
|||
foreach ($final as $key => $data) {
|
||||
$this->set($key, $data);
|
||||
}
|
||||
$this->set('responseType', $responseType);
|
||||
$this->set('returnFormat', $returnFormat);
|
||||
$this->set('renderView', $renderView);
|
||||
$this->render('/Events/eventRestSearchExportResult');
|
||||
} else {
|
||||
|
|
|
@ -392,7 +392,7 @@ class OrganisationsController extends AppController
|
|||
{
|
||||
$this->layout = false;
|
||||
$this->autoRender = false;
|
||||
$this->set('id', $id);
|
||||
$this->set('id', (int)$id);
|
||||
$this->set('removable', $removable);
|
||||
$this->set('extend', $extend);
|
||||
$this->render('ajax/sg_org_row_empty');
|
||||
|
@ -483,6 +483,12 @@ class OrganisationsController extends AppController
|
|||
if ($logo['size'] > 0 && $logo['error'] == 0) {
|
||||
$extension = pathinfo($logo['name'], PATHINFO_EXTENSION);
|
||||
$filename = $orgId . '.' . ($extension === 'svg' ? 'svg' : 'png');
|
||||
|
||||
if ($extension === 'svg' && !Configure::read('Security.enable_svg_logos')) {
|
||||
$this->Flash->error(__('Invalid file extension, SVG images are not allowed.'));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($logo['tmp_name']) && is_uploaded_file($logo['tmp_name'])) {
|
||||
return move_uploaded_file($logo['tmp_name'], APP . 'webroot/img/orgs/' . $filename);
|
||||
}
|
||||
|
|
|
@ -30,7 +30,12 @@ class PagesController extends AppController
|
|||
public function display()
|
||||
{
|
||||
$path = func_get_args();
|
||||
|
||||
foreach ($path as $k => $part) {
|
||||
if (strpos($part, '..') !== false || strpos($part, '/') !== false) {
|
||||
unset($path[$k]);
|
||||
}
|
||||
}
|
||||
$path = array_values($path);
|
||||
$count = count($path);
|
||||
if (!$count) {
|
||||
$this->redirect('/');
|
||||
|
|
|
@ -154,7 +154,7 @@ class UsersController extends AppController
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!$abortPost && !$this->_isRest()) {
|
||||
if (!$abortPost && (!$this->_isRest() || empty($this->request->header('Authorization')))) {
|
||||
if (Configure::read('Security.require_password_confirmation')) {
|
||||
if (!empty($this->request->data['User']['current_password'])) {
|
||||
$hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);
|
||||
|
@ -853,7 +853,7 @@ class UsersController extends AppController
|
|||
$this->request->data['User'] = $this->request->data;
|
||||
}
|
||||
$abortPost = false;
|
||||
if (!$this->_isRest()) {
|
||||
if (!$this->_isRest() || empty($this->request->header('Authorization'))) {
|
||||
if (Configure::read('Security.require_password_confirmation')) {
|
||||
if (!empty($this->request->data['User']['current_password'])) {
|
||||
$hashed = $this->User->verifyPassword($this->Auth->user('id'), $this->request->data['User']['current_password']);
|
||||
|
|
|
@ -94,7 +94,7 @@ class BackgroundJobsTool
|
|||
|
||||
/**
|
||||
* Initialize
|
||||
*
|
||||
*
|
||||
* Settings should have the following format:
|
||||
* [
|
||||
* 'enabled' => true,
|
||||
|
@ -111,6 +111,7 @@ class BackgroundJobsTool
|
|||
* ]
|
||||
*
|
||||
* @param array $settings
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
|
@ -233,8 +234,6 @@ class BackgroundJobsTool
|
|||
* Get the job status.
|
||||
*
|
||||
* @param string $jobId Background Job Id.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public function getJob(string $jobId)
|
||||
{
|
||||
|
@ -366,9 +365,10 @@ class BackgroundJobsTool
|
|||
/**
|
||||
* Start worker by queue
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $queue Queue name
|
||||
* @param boolean $waitForRestart
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function startWorkerByQueue(string $queue, bool $waitForRestart = false): bool
|
||||
{
|
||||
|
@ -401,6 +401,7 @@ class BackgroundJobsTool
|
|||
* @param string|int $id
|
||||
* @param boolean $waitForRestart
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function stopWorker($id, bool $waitForRestart = false): bool
|
||||
{
|
||||
|
@ -428,6 +429,7 @@ class BackgroundJobsTool
|
|||
*
|
||||
* @param boolean $waitForRestart
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function restartWorkers(bool $waitForRestart = false)
|
||||
{
|
||||
|
@ -440,6 +442,7 @@ class BackgroundJobsTool
|
|||
*
|
||||
* @param boolean $waitForRestart
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function restartDeadWorkers(bool $waitForRestart = false)
|
||||
{
|
||||
|
@ -499,6 +502,7 @@ class BackgroundJobsTool
|
|||
* Return true if Supervisor process is running.
|
||||
*
|
||||
* @return boolean
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getSupervisorStatus(): bool
|
||||
{
|
||||
|
@ -508,8 +512,8 @@ class BackgroundJobsTool
|
|||
/**
|
||||
* Validate queue
|
||||
*
|
||||
* @param string $queue
|
||||
* @return boolean
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function validateQueue(string $queue): bool
|
||||
{
|
||||
|
@ -529,8 +533,8 @@ class BackgroundJobsTool
|
|||
/**
|
||||
* Validate command
|
||||
*
|
||||
* @param string $command
|
||||
* @return boolean
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
private function validateCommand(string $command): bool
|
||||
{
|
||||
|
@ -569,9 +573,14 @@ class BackgroundJobsTool
|
|||
|
||||
/**
|
||||
* @return Redis
|
||||
* @throws Exception
|
||||
*/
|
||||
private function createRedisConnection(): Redis
|
||||
{
|
||||
if (!class_exists('Redis')) {
|
||||
throw new Exception("Class Redis doesn't exists. Please install redis extension for PHP.");
|
||||
}
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect($this->settings['redis_host'], $this->settings['redis_port']);
|
||||
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_JSON);
|
||||
|
@ -591,6 +600,7 @@ class BackgroundJobsTool
|
|||
|
||||
/**
|
||||
* @return \Supervisor\Supervisor
|
||||
* @throws Exception
|
||||
*/
|
||||
private function getSupervisor()
|
||||
{
|
||||
|
|
|
@ -251,9 +251,14 @@ class PubSubTool
|
|||
/**
|
||||
* @param array $settings
|
||||
* @return Redis
|
||||
* @throws Exception
|
||||
*/
|
||||
private function createRedisConnection(array $settings)
|
||||
{
|
||||
if (!class_exists('Redis')) {
|
||||
throw new Exception("Class Redis doesn't exists. Please install redis extension for PHP.");
|
||||
}
|
||||
|
||||
$redis = new Redis();
|
||||
$redis->connect($settings['redis_host'], $settings['redis_port']);
|
||||
$redisPassword = $settings['redis_password'];
|
||||
|
|
|
@ -8,7 +8,8 @@ class ServerSyncTool
|
|||
FEATURE_ORG_RULE = 'org_rule',
|
||||
FEATURE_FILTER_SIGHTINGS = 'filter_sightings',
|
||||
FEATURE_PROPOSALS = 'proposals',
|
||||
FEATURE_POST_TEST = 'post_test';
|
||||
FEATURE_POST_TEST = 'post_test',
|
||||
FEATURE_PROTECTED_EVENT = 'protected_event';
|
||||
|
||||
/** @var array */
|
||||
private $server;
|
||||
|
@ -325,6 +326,9 @@ class ServerSyncTool
|
|||
case self::FEATURE_POST_TEST:
|
||||
$version = explode('.', $info['version']);
|
||||
return $version[0] == 2 && $version[1] == 4 && $version[2] > 68;
|
||||
case self::FEATURE_PROTECTED_EVENT:
|
||||
$version = explode('.', $info['version']);
|
||||
return $version[0] == 2 && $version[1] == 4 && $version[2] > 155;
|
||||
default:
|
||||
throw new InvalidArgumentException("Invalid flag `$flag` provided");
|
||||
}
|
||||
|
@ -379,7 +383,12 @@ class ServerSyncTool
|
|||
}
|
||||
|
||||
$request = $this->request;
|
||||
if (strlen($data) > 1024 && !$protectedMode) { // do not compress small body
|
||||
|
||||
if ($protectedMode) {
|
||||
$request['header']['x-pgp-signature'] = $this->signEvent($data);
|
||||
}
|
||||
|
||||
if (strlen($data) > 1024) { // do not compress small body
|
||||
if ($this->isSupported(self::FEATURE_BR) && function_exists('brotli_compress')) {
|
||||
$request['header']['Content-Encoding'] = 'br';
|
||||
$data = brotli_compress($data, 1, BROTLI_TEXT);
|
||||
|
@ -390,9 +399,6 @@ class ServerSyncTool
|
|||
}
|
||||
$url = $this->server['Server']['url'] . $url;
|
||||
$start = microtime(true);
|
||||
if ($protectedMode) {
|
||||
$request = $this->signEvent($data, $this->server, $request, $this->socket);
|
||||
}
|
||||
$response = $this->socket->post($url, $data, $request);
|
||||
$this->log($start, 'POST', $url, $response);
|
||||
if (!$response->isOk()) {
|
||||
|
@ -402,39 +408,22 @@ class ServerSyncTool
|
|||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @param array $server
|
||||
* @param array $request
|
||||
* @param HttpSocket $HttpSocket
|
||||
* @return array
|
||||
* @param string $data Data to sign
|
||||
* @return string base64 encoded signature
|
||||
* @throws Exception
|
||||
* @throws HttpException
|
||||
* @throws MethodNotAllowedException
|
||||
*/
|
||||
private function signEvent($data, $server, $request, $socket)
|
||||
private function signEvent($data)
|
||||
{
|
||||
if (!$this->isSupported(self::FEATURE_PROTECTED_EVENT)) {
|
||||
throw new Exception(__('Remote instance is not protected event aware yet (< 2.4.156), aborting.'));
|
||||
}
|
||||
|
||||
$this->CryptographicKey = ClassRegistry::init('CryptographicKey');
|
||||
$signature = $this->CryptographicKey->signWithInstanceKey($data);
|
||||
$request['header']['x-pgp-signature'] = base64_encode($signature);
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
if (empty($signature)) {
|
||||
$message = __("Invalid signing key. This should never happen.");
|
||||
$this->Log->createLogEntry('SYSTEM', 'push', 'Server', $server['Server']['id'], $message);
|
||||
throw new Exception($message);
|
||||
throw new Exception(__("Invalid signing key. This should never happen."));
|
||||
}
|
||||
$response = $socket->get($server['Server']['url'] . '/servers/getVersion.json', null, $request);
|
||||
if (!$response->isOk()) {
|
||||
$message = __("Could not fetch remote version to negotiate protected event synchronisation.");
|
||||
$this->Log->createLogEntry('SYSTEM', 'push', 'Server', $server['Server']['id'], $message);
|
||||
throw new HttpException($response->body, $response->code);
|
||||
}
|
||||
$version = json_decode($response->body(), true)['version'];
|
||||
if (version_compare($version, '2.4.156') < 0) {
|
||||
$message = __('Remote instance is not protected event aware yet (< 2.4.156), aborting.');
|
||||
$this->Log->createLogEntry('SYSTEM', 'push', 'Server', $server['Server']['id'], $message);
|
||||
throw new MethodNotAllowedException($message);
|
||||
}
|
||||
return $request;
|
||||
return base64_encode($signature);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -51,6 +51,9 @@ class AppModel extends Model
|
|||
{
|
||||
parent::__construct($id, $table, $ds);
|
||||
$this->findMethods['column'] = true;
|
||||
if (in_array('phar', stream_get_wrappers())) {
|
||||
stream_wrapper_unregister('phar');
|
||||
}
|
||||
}
|
||||
|
||||
// deprecated, use $db_changes
|
||||
|
@ -2539,7 +2542,7 @@ class AppModel extends Model
|
|||
}
|
||||
|
||||
if (!class_exists('Redis')) {
|
||||
throw new Exception("Class Redis doesn't exists.");
|
||||
throw new Exception("Class Redis doesn't exists. Please install redis extension for PHP.");
|
||||
}
|
||||
|
||||
$host = Configure::read('MISP.redis_host') ?: '127.0.0.1';
|
||||
|
@ -2585,6 +2588,7 @@ class AppModel extends Model
|
|||
App::uses('KafkaPubTool', 'Tools');
|
||||
$kafkaPubTool = new KafkaPubTool();
|
||||
$rdkafkaIni = Configure::read('Plugin.Kafka_rdkafka_config');
|
||||
$rdkafkaIni = mb_ereg_replace("/\:\/\//", '', $rdkafkaIni);
|
||||
$kafkaConf = array();
|
||||
if (!empty($rdkafkaIni)) {
|
||||
$kafkaConf = parse_ini_file($rdkafkaIni);
|
||||
|
|
|
@ -580,7 +580,13 @@ class Attribute extends AppModel
|
|||
$this->validationErrors['type'] = ['No type set.'];
|
||||
return false;
|
||||
}
|
||||
|
||||
$type = $attribute['type'];
|
||||
if (!isset($this->typeDefinitions[$type])) {
|
||||
$this->validationErrors['type'] = ['Invalid type.'];
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($attribute['value'])) {
|
||||
$this->validationErrors['value'] = ['Value is an array.'];
|
||||
return false;
|
||||
|
|
|
@ -24,7 +24,8 @@ class CryptographicKey extends AppModel
|
|||
|
||||
const ERROR_MALFORMED_SIGNATURE = 'Malformed signature',
|
||||
ERROR_INVALID_SIGNATURE = 'Invalid signature',
|
||||
ERROR_WRONG_KEY = 'Wrong key';
|
||||
ERROR_WRONG_KEY = 'Wrong key',
|
||||
ERROR_INVALID_KEY = 'Invalid key';
|
||||
|
||||
public $validTypes = [
|
||||
'pgp'
|
||||
|
@ -98,6 +99,9 @@ class CryptographicKey extends AppModel
|
|||
if (empty($fingerprint)) {
|
||||
$file = new File(APP . '/webroot/gpg.asc');
|
||||
$instanceKey = $file->read();
|
||||
if (!$this->gpg) {
|
||||
throw new MethodNotAllowedException("Could not initiate GPG");
|
||||
}
|
||||
try {
|
||||
$this->gpg->importKey($instanceKey);
|
||||
} catch (Crypt_GPG_NoDataException $e) {
|
||||
|
@ -108,7 +112,14 @@ class CryptographicKey extends AppModel
|
|||
$redis->setEx($redisKey, 300, $fingerprint);
|
||||
}
|
||||
}
|
||||
$this->gpg->addSignKey(Configure::read('GnuPG.email'), Configure::read('GnuPG.password'));
|
||||
if (!$this->gpg) {
|
||||
throw new MethodNotAllowedException("Could not initiate GPG");
|
||||
}
|
||||
try {
|
||||
$this->gpg->addSignKey(Configure::read('GnuPG.email'), Configure::read('GnuPG.password'));
|
||||
} catch (Exception $e) {
|
||||
throw new NotFoundException('Could not add signing key.');
|
||||
}
|
||||
return $fingerprint;
|
||||
}
|
||||
|
||||
|
@ -135,25 +146,29 @@ class CryptographicKey extends AppModel
|
|||
{
|
||||
$this->error = false;
|
||||
$fingerprint = $this->__extractPGPKeyData($key);
|
||||
if ($fingerprint === false) {
|
||||
$this->error = self::ERROR_INVALID_KEY;
|
||||
return false;
|
||||
}
|
||||
$data = preg_replace("/\s+/", "", $data);
|
||||
try {
|
||||
$verifiedSignature = $this->gpg->verify($data, $signature);
|
||||
} catch (Exception $e) {
|
||||
$this->error = $this::ERROR_WRONG_KEY;
|
||||
$this->error = self::ERROR_WRONG_KEY;
|
||||
return false;
|
||||
}
|
||||
if (empty($verifiedSignature)) {
|
||||
$this->error = $this::ERROR_MALFORMED_SIGNATURE;
|
||||
$this->error = self::ERROR_MALFORMED_SIGNATURE;
|
||||
return false;
|
||||
}
|
||||
if (!$verifiedSignature[0]->isValid()) {
|
||||
$this->error = $this::ERROR_INVALID_SIGNATURE;
|
||||
$this->error = self::ERROR_INVALID_SIGNATURE;
|
||||
return false;
|
||||
}
|
||||
if ($verifiedSignature[0]->getKeyFingerprint() === $fingerprint) {
|
||||
return true;
|
||||
} else {
|
||||
$this->error = $this::ERROR_WRONG_KEY;
|
||||
$this->error = self::ERROR_WRONG_KEY;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -168,19 +183,22 @@ class CryptographicKey extends AppModel
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @return string|false Primary key fingerprint or false of key is invalid
|
||||
*/
|
||||
private function __extractPGPKeyData($data)
|
||||
{
|
||||
try {
|
||||
$gpgTool = new GpgTool($this->gpg);
|
||||
} catch (Exception $e) {
|
||||
$this->logException("GPG couldn't be initialized, GPG encryption and signing will be not available.", $e, LOG_NOTICE);
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
return $gpgTool->validateGpgKey($data);
|
||||
} catch (Exception $e) {
|
||||
$this->logException("Could not validate PGP key.", $e, LOG_NOTICE);
|
||||
return '';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +259,6 @@ class CryptographicKey extends AppModel
|
|||
{
|
||||
$existingKeys = $this->find('first', [
|
||||
'recursive' => -1,
|
||||
'fields' => 1,
|
||||
'conditions' => [
|
||||
'parent_type' => $type,
|
||||
'parent_id' => $parent_id
|
||||
|
|
|
@ -17,6 +17,7 @@ App::uses('ProcessTool', 'Tools');
|
|||
* @property ThreatLevel $ThreatLevel
|
||||
* @property Sighting $Sighting
|
||||
* @property Organisation $Org
|
||||
* @property CryptographicKey $CryptographicKey
|
||||
*/
|
||||
class Event extends AppModel
|
||||
{
|
||||
|
@ -4430,6 +4431,7 @@ class Event extends AppModel
|
|||
$servers = $this->Server->find('all', [
|
||||
'conditions' => $conditions,
|
||||
'recursive' => -1,
|
||||
'contain' => ['RemoteOrg', 'Organisation'],
|
||||
'order' => ['Server.priority ASC', 'Server.id ASC'],
|
||||
]);
|
||||
// iterate over the servers and upload the event
|
||||
|
@ -6173,18 +6175,10 @@ class Event extends AppModel
|
|||
$newTextBody = JsonTool::encode($newTextBody);
|
||||
}
|
||||
|
||||
$this->Log = ClassRegistry::init('Log');
|
||||
$this->Log->create();
|
||||
$this->Log->save(array(
|
||||
'org' => 'SYSTEM',
|
||||
'model' => 'Server',
|
||||
'model_id' => $server['Server']['id'],
|
||||
'email' => 'SYSTEM',
|
||||
'action' => 'warning',
|
||||
'user_id' => 0,
|
||||
'title' => 'Uploading Event (' . $event['Event']['id'] . ') to Server (' . $server['Server']['id'] . ')',
|
||||
'change' => 'Returned message: ' . $newTextBody,
|
||||
));
|
||||
$title = 'Uploading Event (' . $event['Event']['id'] . ') to Server (' . $server['Server']['id'] . ')';
|
||||
$change = 'Returned message: ' . $newTextBody;
|
||||
|
||||
$this->loadLog()->createLogEntry('SYSTEM', 'warning', 'Server', $server['Server']['id'], $title, $change);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -126,12 +126,13 @@ class Feed extends AppModel
|
|||
public function urlOrExistingFilepath($fields)
|
||||
{
|
||||
if ($this->isFeedLocal($this->data)) {
|
||||
$path = mb_ereg_replace("/\:\/\//", '', $this->data['Feed']['url']);
|
||||
if ($this->data['Feed']['source_format'] == 'misp') {
|
||||
if (!is_dir($this->data['Feed']['url'])) {
|
||||
if (!is_dir($path)) {
|
||||
return 'For MISP type local feeds, please specify the containing directory.';
|
||||
}
|
||||
} else {
|
||||
if (!file_exists($this->data['Feed']['url'])) {
|
||||
if (!file_exists($path)) {
|
||||
return 'Invalid path or file not found. Make sure that the path points to an existing file that is readable and watch out for typos.';
|
||||
}
|
||||
}
|
||||
|
@ -1929,6 +1930,7 @@ class Feed extends AppModel
|
|||
private function feedGetUri($feed, $uri, HttpSocket $HttpSocket = null)
|
||||
{
|
||||
if ($this->isFeedLocal($feed)) {
|
||||
$uri = mb_ereg_replace("/\:\/\//", '', $uri);
|
||||
if (file_exists($uri)) {
|
||||
return FileAccessTool::readFromFile($uri);
|
||||
} else {
|
||||
|
|
|
@ -4683,6 +4683,14 @@ class Server extends AppModel
|
|||
'type' => 'numeric',
|
||||
'null' => true
|
||||
),
|
||||
'disable_event_locks' => [
|
||||
'level' => 1,
|
||||
'description' => __('Disable the event locks that are executed periodically when a user browses an event view. It can be useful to leave event locks enabled to warn users that someone else is editing the same event, but generally it\'s extremely verbose and can cause issues in certain setups, so it\'s recommended to disable this.'),
|
||||
'value' => false,
|
||||
'test' => 'testBoolTrue',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
],
|
||||
'enable_advanced_correlations' => array(
|
||||
'level' => 0,
|
||||
'description' => __('Enable some performance heavy correlations (currently CIDR correlation)'),
|
||||
|
@ -5867,7 +5875,8 @@ class Server extends AppModel
|
|||
'value' => false,
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
'null' => true,
|
||||
'cli_only' => 1
|
||||
),
|
||||
'rest_client_baseurl' => array(
|
||||
'level' => 1,
|
||||
|
@ -6136,6 +6145,14 @@ class Server extends AppModel
|
|||
'tlsv1_3' => 'TLSv1.3',
|
||||
],
|
||||
],
|
||||
'enable_svg_logos' => [
|
||||
'level' => self::SETTING_OPTIONAL,
|
||||
'description' => __('When enabled, organisations logos in svg format are allowed.'),
|
||||
'value' => false,
|
||||
'test' => 'testBool',
|
||||
'type' => 'boolean',
|
||||
'null' => true
|
||||
]
|
||||
),
|
||||
'SecureAuth' => array(
|
||||
'branch' => 1,
|
||||
|
@ -7112,6 +7129,12 @@ class Server extends AppModel
|
|||
),
|
||||
'LinOTPAuth' => array(
|
||||
'branch' => 1,
|
||||
'enabled' => array(
|
||||
'level' => 2,
|
||||
'description' => __('Enable / Disable LinOTP'),
|
||||
'value' => true,
|
||||
'type' => 'boolean',
|
||||
),
|
||||
'baseUrl' => array(
|
||||
'level' => 2,
|
||||
'description' => __('The default LinOTP URL.'),
|
||||
|
|
|
@ -21,274 +21,275 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth');
|
|||
|
||||
class CertificateAuthenticate extends BaseAuthenticate
|
||||
{
|
||||
/**
|
||||
* Holds the certificate issuer information (available at SSL_CLIENT_I_DN)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $ca;
|
||||
/**
|
||||
* Holds the certificate issuer information (available at SSL_CLIENT_I_DN)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $ca;
|
||||
|
||||
/**
|
||||
* Holds the certificate user information (available at SSL_CLIENT_S_DN)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $client;
|
||||
/**
|
||||
* Holds the certificate user information (available at SSL_CLIENT_S_DN)
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $client;
|
||||
|
||||
/**
|
||||
* Holds the user information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $user;
|
||||
/**
|
||||
* Holds the user information
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $user;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* This should only be called once per request, so it doesn't need to store values in
|
||||
* the instance. Simply checks if the certificate is valid (against configured valid issuers)
|
||||
* and returns the user information encoded.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::$ca = self::$client = false;
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* This should only be called once per request, so it doesn't need to store values in
|
||||
* the instance. Simply checks if the certificate is valid (against configured valid issuers)
|
||||
* and returns the user information encoded.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::$ca = self::$client = false;
|
||||
|
||||
if (isset($_SERVER['SSL_CLIENT_I_DN'])) {
|
||||
$CA = self::parse($_SERVER['SSL_CLIENT_I_DN'], Configure::read('CertAuth.mapCa'));
|
||||
// only valid CAs, if this was configured
|
||||
if ($ca=Configure::read('CertAuth.ca')) {
|
||||
$k = Configure::read('CertAuth.caId');
|
||||
if (!$k) $k = 'CN';
|
||||
$id = (isset($CA[$k]))?($CA[$k]):(false);
|
||||
if (isset($_SERVER['SSL_CLIENT_I_DN'])) {
|
||||
$CA = self::parse($_SERVER['SSL_CLIENT_I_DN'], Configure::read('CertAuth.mapCa'));
|
||||
// only valid CAs, if this was configured
|
||||
if ($ca=Configure::read('CertAuth.ca')) {
|
||||
$k = Configure::read('CertAuth.caId');
|
||||
if (!$k) $k = 'CN';
|
||||
$id = (isset($CA[$k]))?($CA[$k]):(false);
|
||||
|
||||
if (!$id) {
|
||||
$CA = false;
|
||||
} else if (is_array($ca)) {
|
||||
if (!in_array($id, $ca)) $CA = false;
|
||||
} else if ($ca!=$id) {
|
||||
$CA = false;
|
||||
}
|
||||
unset($id, $k);
|
||||
}
|
||||
self::$ca = $CA;
|
||||
unset($CA, $ca);
|
||||
}
|
||||
if (!$id) {
|
||||
$CA = false;
|
||||
} else if (is_array($ca)) {
|
||||
if (!in_array($id, $ca)) $CA = false;
|
||||
} else if ($ca!=$id) {
|
||||
$CA = false;
|
||||
}
|
||||
unset($id, $k);
|
||||
}
|
||||
self::$ca = $CA;
|
||||
unset($CA, $ca);
|
||||
}
|
||||
|
||||
if (self::$ca) {
|
||||
$map = Configure::read('CertAuth.map');
|
||||
if(isset($_SERVER['SSL_CLIENT_S_DN'])) {
|
||||
self::$client = self::parse($_SERVER['SSL_CLIENT_S_DN'], $map);
|
||||
} else {
|
||||
self::$client = array();
|
||||
}
|
||||
foreach($map as $n=>$d) {
|
||||
if(isset($_SERVER[$n])) {
|
||||
self::$client[$d] = $_SERVER[$n];
|
||||
}
|
||||
unset($map[$n], $n, $d);
|
||||
}
|
||||
unset($map);
|
||||
if(!self::$client) {
|
||||
self::$client = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self::$ca) {
|
||||
$map = Configure::read('CertAuth.map');
|
||||
if(isset($_SERVER['SSL_CLIENT_S_DN'])) {
|
||||
self::$client = self::parse($_SERVER['SSL_CLIENT_S_DN'], $map);
|
||||
} else {
|
||||
self::$client = array();
|
||||
}
|
||||
foreach($map as $n=>$d) {
|
||||
if(isset($_SERVER[$n])) {
|
||||
self::$client[$d] = $_SERVER[$n];
|
||||
}
|
||||
unset($map[$n], $n, $d);
|
||||
}
|
||||
unset($map);
|
||||
if(!self::$client) {
|
||||
self::$client = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse certificate extensions
|
||||
*
|
||||
* @TODO this should properly address the RFC
|
||||
* @param string $s text to be parsed
|
||||
* @param (optional) array $map array of mapping extension to User fields
|
||||
* @return array parsed values
|
||||
*/
|
||||
private static function parse($s, $map=null)
|
||||
{
|
||||
$r=array();
|
||||
if (preg_match_all('#(^/?|\/|\,)([a-zA-Z]+)\=([^\/\,]+)#', $s, $m)) {
|
||||
foreach ($m[2] as $i=>$k) {
|
||||
if ($map) {
|
||||
if (isset($map[$k])) {
|
||||
$k = $map[$k];
|
||||
} else {
|
||||
$k = null;
|
||||
}
|
||||
}
|
||||
if ($k) {
|
||||
$v = $m[3][$i];
|
||||
$r[$k] = $v;
|
||||
}
|
||||
unset($m[0][$i], $m[1][$i], $m[2][$i], $m[3][$i], $k, $v, $i);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
/**
|
||||
* Parse certificate extensions
|
||||
*
|
||||
* @TODO this should properly address the RFC
|
||||
* @param string $s text to be parsed
|
||||
* @param (optional) array $map array of mapping extension to User fields
|
||||
* @return array parsed values
|
||||
*/
|
||||
private static function parse($s, $map=null)
|
||||
{
|
||||
$r=array();
|
||||
if (preg_match_all('#(^/?|\/|\,)([a-zA-Z]+)\=([^\/\,]+)#', $s, $m)) {
|
||||
foreach ($m[2] as $i=>$k) {
|
||||
if ($map) {
|
||||
if (isset($map[$k])) {
|
||||
$k = $map[$k];
|
||||
} else {
|
||||
$k = null;
|
||||
}
|
||||
}
|
||||
if ($k) {
|
||||
$v = $m[3][$i];
|
||||
$r[$k] = $v;
|
||||
}
|
||||
unset($m[0][$i], $m[1][$i], $m[2][$i], $m[3][$i], $k, $v, $i);
|
||||
}
|
||||
}
|
||||
return $r;
|
||||
}
|
||||
|
||||
// to enable stateless authentication
|
||||
public function getUser(CakeRequest $request)
|
||||
{
|
||||
if (empty(self::$user)) {
|
||||
if (self::$client) {
|
||||
self::$user = self::$client;
|
||||
// If $sync is true, allow the creation of the user from the certificate
|
||||
$sync = Configure::read('CertAuth.syncUser');
|
||||
$url = Configure::read('CertAuth.restApi.url');
|
||||
if ($sync && $url) {
|
||||
if (!self::getRestUser()) return false;
|
||||
}
|
||||
// to enable stateless authentication
|
||||
public function getUser(CakeRequest $request)
|
||||
{
|
||||
if (empty(self::$user)) {
|
||||
if (self::$client) {
|
||||
self::$user = self::$client;
|
||||
// If $sync is true, allow the creation of the user from the certificate
|
||||
$sync = Configure::read('CertAuth.syncUser');
|
||||
$url = Configure::read('CertAuth.restApi.url');
|
||||
if ($sync && $url) {
|
||||
if (!self::getRestUser()) return false;
|
||||
}
|
||||
|
||||
// find and fill user with model
|
||||
$userModelKey = empty(Configure::read('CertAuth.userModelKey')) ? 'email' : Configure::read('CertAuth.userModelKey');
|
||||
$userDefaults = Configure::read('CertAuth.userDefaults');
|
||||
$this->User = ClassRegistry::init('User');
|
||||
if (!empty(self::$user[$userModelKey])) {
|
||||
$existingUser = $this->User->find('first', array(
|
||||
'conditions' => array($userModelKey => self::$user[$userModelKey]),
|
||||
'recursive' => false
|
||||
));
|
||||
}
|
||||
if ($existingUser) {
|
||||
if ($sync) {
|
||||
if (!isset(self::$user['org_id']) && isset(self::$user['org'])) {
|
||||
self::$user['org_id'] = $this->User->Organisation->createOrgFromName(self::$user['org'], $existingUser['User']['id'], true);
|
||||
// reset user defaults in case it's a different org_id
|
||||
if (self::$user['org_id'] && $existingUser['User']['org_id'] != self::$user['org_id']) {
|
||||
if ($userDefaults && is_array($userDefaults)) {
|
||||
self::$user = array_merge($userDefaults + self::$user);
|
||||
}
|
||||
}
|
||||
unset(self::$user['org']);
|
||||
}
|
||||
$write = array();
|
||||
foreach (self::$user as $k => $v) {
|
||||
if (isset($existingUser['User'][$k]) && trim($existingUser['User'][$k]) != trim($v)) {
|
||||
$write[] = $k;
|
||||
$existingUser['User'][$k] = trim($v);
|
||||
}
|
||||
}
|
||||
if (!empty($write) && !$this->User->save($existingUser['User'], true, $write)) {
|
||||
CakeLog::write('alert', 'Could not update model at database with RestAPI data.');
|
||||
}
|
||||
}
|
||||
self::$user = $this->User->getAuthUser($existingUser['User']['id']);
|
||||
if (isset(self::$user['gpgkey'])) unset(self::$user['gpgkey']);
|
||||
} else if ($sync && !empty(self::$user)) {
|
||||
$org = isset(self::$client['org']) ? self::$client['org'] : null;
|
||||
if ($org == null) return false;
|
||||
if (!isset(self::$user['org_id']) && isset(self::$user['org'])) {
|
||||
self::$user['org_id'] = $this->User->Organisation->createOrgFromName($org, 0, true);
|
||||
unset(self::$user['org']);
|
||||
}
|
||||
if ($userDefaults && is_array($userDefaults)) {
|
||||
self::$user = array_merge(self::$user, $userDefaults);
|
||||
}
|
||||
$this->User->create();
|
||||
if ($this->User->save(self::$user)) {
|
||||
$id = $this->User->id;
|
||||
self::$user = $this->User->getAuthUser($id);
|
||||
if (isset(self::$user['gpgkey'])) unset(self::$user['gpgkey']);
|
||||
} else {
|
||||
CakeLog::write('alert', 'Could not insert model at database from RestAPI data. Reason: ' . json_encode($this->User->validationErrors));
|
||||
}
|
||||
} else {
|
||||
// No match -- User doesn't exist !!!
|
||||
self::$user = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$user;
|
||||
}
|
||||
// find and fill user with model
|
||||
$userModelKey = empty(Configure::read('CertAuth.userModelKey')) ? 'email' : Configure::read('CertAuth.userModelKey');
|
||||
$userDefaults = Configure::read('CertAuth.userDefaults');
|
||||
$this->User = ClassRegistry::init('User');
|
||||
if (!empty(self::$user[$userModelKey])) {
|
||||
$existingUser = $this->User->find('first', array(
|
||||
'conditions' => array($userModelKey => self::$user[$userModelKey]),
|
||||
'recursive' => false
|
||||
));
|
||||
}
|
||||
if ($existingUser) {
|
||||
if ($sync) {
|
||||
if (!isset(self::$user['org_id']) && isset(self::$user['org'])) {
|
||||
self::$user['org_id'] = $this->User->Organisation->createOrgFromName(self::$user['org'], $existingUser['User']['id'], true);
|
||||
// reset user defaults in case it's a different org_id
|
||||
if (self::$user['org_id'] && $existingUser['User']['org_id'] != self::$user['org_id']) {
|
||||
if ($userDefaults && is_array($userDefaults)) {
|
||||
self::$user = array_merge($userDefaults + self::$user);
|
||||
}
|
||||
}
|
||||
unset(self::$user['org']);
|
||||
}
|
||||
$write = array();
|
||||
foreach (self::$user as $k => $v) {
|
||||
if (isset($existingUser['User'][$k]) && trim($existingUser['User'][$k]) != trim($v)) {
|
||||
$write[] = $k;
|
||||
$existingUser['User'][$k] = trim($v);
|
||||
}
|
||||
}
|
||||
if (!empty($write) && !$this->User->save($existingUser['User'], true, $write)) {
|
||||
CakeLog::write('alert', 'Could not update model at database with RestAPI data.');
|
||||
}
|
||||
}
|
||||
self::$user = $this->User->getAuthUser($existingUser['User']['id']);
|
||||
if (isset(self::$user['gpgkey'])) unset(self::$user['gpgkey']);
|
||||
} else if ($sync && !empty(self::$user)) {
|
||||
$org = isset(self::$client['org']) ? self::$client['org'] : null;
|
||||
if ($org == null) return false;
|
||||
if (!isset(self::$user['org_id']) && isset(self::$user['org'])) {
|
||||
self::$user['org_id'] = $this->User->Organisation->createOrgFromName($org, 0, true);
|
||||
unset(self::$user['org']);
|
||||
}
|
||||
if ($userDefaults && is_array($userDefaults)) {
|
||||
self::$user = array_merge(self::$user, $userDefaults);
|
||||
}
|
||||
$this->User->create();
|
||||
if ($this->User->save(self::$user)) {
|
||||
$id = $this->User->id;
|
||||
self::$user = $this->User->getAuthUser($id);
|
||||
if (isset(self::$user['gpgkey'])) unset(self::$user['gpgkey']);
|
||||
} else {
|
||||
CakeLog::write('alert', 'Could not insert model at database from RestAPI data. Reason: ' . json_encode($this->User->validationErrors));
|
||||
}
|
||||
} else {
|
||||
// No match -- User doesn't exist !!!
|
||||
self::$user = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::$user;
|
||||
}
|
||||
|
||||
// to enable stateless authentication
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response)
|
||||
{
|
||||
return self::getUser($request);
|
||||
}
|
||||
// to enable stateless authentication
|
||||
public function authenticate(CakeRequest $request, CakeResponse $response)
|
||||
{
|
||||
return self::getUser($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches user information from external REST API
|
||||
*
|
||||
* Valid options (should be configured under CertAuth.restApi):
|
||||
*
|
||||
* @param (optional) array $options API configuration
|
||||
* url (string) Where to fetch information from
|
||||
* headers (array) list of additional headers to be used, reserved for authentication tokens
|
||||
* params (array) mapping of additional params to be included at the url, uses $user values
|
||||
* map (array) mapping of the return values to be added to the self::$user
|
||||
* @return array updated user object
|
||||
*/
|
||||
public function getRestUser($options=null, $user=null)
|
||||
{
|
||||
if (is_null($options)) {
|
||||
$options = Configure::read('CertAuth.restApi');
|
||||
}
|
||||
if (!is_null($user)) {
|
||||
self::$user = $user;
|
||||
}
|
||||
/**
|
||||
* Fetches user information from external REST API
|
||||
*
|
||||
* Valid options (should be configured under CertAuth.restApi):
|
||||
*
|
||||
* @param (optional) array $options API configuration
|
||||
* url (string) Where to fetch information from
|
||||
* headers (array) list of additional headers to be used, reserved for authentication tokens
|
||||
* params (array) mapping of additional params to be included at the url, uses $user values
|
||||
* map (array) mapping of the return values to be added to the self::$user
|
||||
* @return array updated user object
|
||||
*/
|
||||
public function getRestUser($options=null, $user=null)
|
||||
{
|
||||
if (is_null($options)) {
|
||||
$options = Configure::read('CertAuth.restApi');
|
||||
}
|
||||
if (!is_null($user)) {
|
||||
self::$user = $user;
|
||||
}
|
||||
|
||||
if (!isset($options['url'])) {
|
||||
return null;
|
||||
}
|
||||
if (!isset($options['url'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create a stream
|
||||
$req = array(
|
||||
'http'=>array(
|
||||
'method'=>'GET',
|
||||
'header'=>"Accept: application/json\r\n"
|
||||
),
|
||||
);
|
||||
if (isset($options['headers'])) {
|
||||
foreach ($options['headers'] as $k=>$v) {
|
||||
if (is_int($k)) {
|
||||
$req['header'] .= "{$v}\r\n";
|
||||
} else {
|
||||
$req['header'] .= "{$k}: {$v}\r\n";
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
// Create a stream
|
||||
$req = array(
|
||||
'http'=>array(
|
||||
'method'=>'GET',
|
||||
'header'=>"Accept: application/json\r\n"
|
||||
),
|
||||
);
|
||||
if (isset($options['headers'])) {
|
||||
foreach ($options['headers'] as $k=>$v) {
|
||||
if (is_int($k)) {
|
||||
$req['header'] .= "{$v}\r\n";
|
||||
} else {
|
||||
$req['header'] .= "{$k}: {$v}\r\n";
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
$url = $options['url'];
|
||||
if (isset($options['param'])) {
|
||||
foreach ($options['param'] as $k=>$v) {
|
||||
if (isset(self::$user[$v])) {
|
||||
$url .= ((strpos($url, '?'))?('&'):('?'))
|
||||
. $k . '=' . urlencode(self::$user[$v]);
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
$ctx = stream_context_create($req);
|
||||
$a = file_get_contents($url, false, $ctx);
|
||||
if (!$a) return null;
|
||||
$url = $options['url'];
|
||||
if (isset($options['param'])) {
|
||||
foreach ($options['param'] as $k=>$v) {
|
||||
if (isset(self::$user[$v])) {
|
||||
$url .= ((strpos($url, '?'))?('&'):('?'))
|
||||
. $k . '=' . urlencode(self::$user[$v]);
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
$ctx = stream_context_create($req);
|
||||
$url = mb_ereg_replace("/phar\:\/\//i", '', $url);
|
||||
$a = file_get_contents($url, false, $ctx);
|
||||
if (!$a) return null;
|
||||
|
||||
$A = json_decode($a, true);
|
||||
if (!isset($A['data'][0])) {
|
||||
self::$user = false;
|
||||
} else if (isset($options['map'])) {
|
||||
foreach ($options['map'] as $k=>$v) {
|
||||
if (isset($A['data'][0][$k])) {
|
||||
self::$user[$v] = $A['data'][0][$k];
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
$A = json_decode($a, true);
|
||||
if (!isset($A['data'][0])) {
|
||||
self::$user = false;
|
||||
} else if (isset($options['map'])) {
|
||||
foreach ($options['map'] as $k=>$v) {
|
||||
if (isset($A['data'][0][$k])) {
|
||||
self::$user[$v] = $A['data'][0][$k];
|
||||
}
|
||||
unset($k, $v);
|
||||
}
|
||||
}
|
||||
|
||||
return self::$user;
|
||||
}
|
||||
return self::$user;
|
||||
}
|
||||
|
||||
protected static $instance;
|
||||
protected static $instance;
|
||||
|
||||
public static function ca()
|
||||
{
|
||||
if (is_null(self::$ca)) new CertificateAuthenticate();
|
||||
return self::$ca;
|
||||
}
|
||||
public static function ca()
|
||||
{
|
||||
if (is_null(self::$ca)) new CertificateAuthenticate();
|
||||
return self::$ca;
|
||||
}
|
||||
|
||||
public static function client()
|
||||
{
|
||||
if (is_null(self::$client)) new CertificateAuthenticate();
|
||||
return self::$client;
|
||||
}
|
||||
public static function client()
|
||||
{
|
||||
if (is_null(self::$client)) new CertificateAuthenticate();
|
||||
return self::$client;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -123,6 +123,13 @@ class LinOTPAuthenticate extends BaseAuthenticate
|
|||
|
||||
CakeLog::debug("getUser email: ${email}");
|
||||
|
||||
$linOTP_enabled = Configure::read("LinOTPAuth.enabled");
|
||||
if (is_null($linOTP_enabled)) {
|
||||
$linOTP_enabled = TRUE;
|
||||
}
|
||||
if (!$linOTP_enabled) {
|
||||
return false;
|
||||
}
|
||||
$linOTP_baseUrl = rtrim(Configure::read("LinOTPAuth.baseUrl"), "/");
|
||||
$linOTP_realm = Configure::read("LinOTPAuth.realm");
|
||||
$linOTP_verifyssl = Configure::read("LinOTPAuth.verifyssl");
|
||||
|
@ -131,7 +138,7 @@ class LinOTPAuthenticate extends BaseAuthenticate
|
|||
if (!$linOTP_baseUrl || $linOTP_baseUrl === "") {
|
||||
CakeLog::error("LinOTP: Please configure baseUrl.");
|
||||
if ($mixedauth) {
|
||||
throw new CakeException(__d('cake_dev', 'LinOTP: Missing "baseUrl" configuration - access denied!', 'authenticate()'));
|
||||
throw new ForbiddenException(__('LinOTP: Missing "baseUrl" configuration - access denied!'));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -150,7 +157,7 @@ class LinOTPAuthenticate extends BaseAuthenticate
|
|||
} else {
|
||||
// Enforce OTP token by Authentication Form
|
||||
if (!$otp || $otp === "") {
|
||||
throw new CakeException(__d('cake_dev', 'Missing OTP Token.', 'authenticate()'));
|
||||
throw new ForbiddenException(__('Missing OTP Token.'));
|
||||
}
|
||||
|
||||
$response = $this->_linotp_verify(
|
||||
|
@ -200,7 +207,7 @@ class LinOTPAuthenticate extends BaseAuthenticate
|
|||
// Don't fall back to FormAuthenticate in mixedauth mode.
|
||||
// This enforces the second factor.
|
||||
if ($mixedauth && !self::$user) {
|
||||
throw new CakeException(__d('cake_dev', 'User could not be authenticated by LinOTP.', 'authenticate()'));
|
||||
throw new UnauthorizedException(__('User could not be authenticated by LinOTP.'));
|
||||
}
|
||||
return self::$user;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ to login with passwords stored in MISP.
|
|||
|
||||
```
|
||||
cd app
|
||||
php composer.phar require jumbojett/openid-connect-php
|
||||
php composer.phar require jakub-onderka/openid-connect-php:1.0.0-rc1
|
||||
```
|
||||
|
||||
2. Enable in `app/Config/config.php`
|
||||
|
|
|
@ -16,15 +16,9 @@
|
|||
'type' => 'simple',
|
||||
'fa-icon' => 'plus',
|
||||
'text' => __('Add authentication key'),
|
||||
'class' => 'btn btn-primary',
|
||||
'onClick' => 'openGenericModal',
|
||||
'onClickParams' => [
|
||||
sprintf(
|
||||
'%s/auth_keys/add%s',
|
||||
$baseurl,
|
||||
empty($user_id) ? '' : ('/' . $user_id)
|
||||
)
|
||||
]
|
||||
'class' => 'btn-primary modal-open',
|
||||
'url' => "$baseurl/auth_keys/add" . (empty($user_id) ? '' : ('/' . $user_id)),
|
||||
'requirement' => $canCreateAuthkey
|
||||
]
|
||||
]
|
||||
],
|
||||
|
@ -101,11 +95,9 @@
|
|||
'title' => 'Edit auth key',
|
||||
],
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/authKeys/delete/[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'AuthKey.id',
|
||||
'class' => 'modal-open',
|
||||
'url' => "$baseurl/authKeys/delete",
|
||||
'url_params_data_paths' => ['AuthKey.id'],
|
||||
'icon' => 'trash',
|
||||
'title' => __('Delete auth key'),
|
||||
]
|
||||
|
|
|
@ -68,7 +68,15 @@
|
|||
<script type="text/javascript">
|
||||
var showContext = false;
|
||||
$(function () {
|
||||
queryEventLock('<?= h($event['Event']['id']); ?>', <?= (int)$event['Event']['timestamp'] ?>);
|
||||
<?php
|
||||
if (!Configure::check('MISP.disable_event_locks') || !Configure::read('MISP.disable_event_locks')) {
|
||||
echo sprintf(
|
||||
"queryEventLock('%s', %s);",
|
||||
h($event['Event']['id']),
|
||||
(int)$event['Event']['timestamp']
|
||||
);
|
||||
}
|
||||
?>
|
||||
popoverStartup();
|
||||
|
||||
$(document.body).tooltip({
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<tr id="event_<?= $eventId ?>">
|
||||
<?php if ($isSiteAdmin || ($event['Event']['orgc_id'] == $me['org_id'])):?>
|
||||
<td style="width:10px;">
|
||||
<input class="select" type="checkbox" data-id="<?= $eventId ?>" />
|
||||
<input class="select" type="checkbox" data-id="<?= $eventId ?>" data-uuid="<?= h($event['Event']['uuid']) ?>" />
|
||||
</td>
|
||||
<?php else: ?>
|
||||
<td style="padding-left:0;padding-right:0;"></td>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
<?php
|
||||
$eventId = (int) $event['Event']['id'];
|
||||
if (!empty($this->passedArgs['correlation'])) {
|
||||
$attributeFilter = 'correlation';
|
||||
}
|
||||
|
@ -28,7 +29,7 @@
|
|||
'text' => __('Proposal'),
|
||||
'active' => $attributeFilter == 'proposal',
|
||||
'onClick' => 'filterAttributes',
|
||||
'onClickParams' => array('proposal', $event['Event']['id'])
|
||||
'onClickParams' => array('proposal', $eventId)
|
||||
);
|
||||
$simple_filter_data[] = array(
|
||||
'id' => 'filter_correlation',
|
||||
|
@ -44,7 +45,7 @@
|
|||
'text' => __('Warning'),
|
||||
'active' => $attributeFilter == 'warning',
|
||||
'onClick' => 'filterAttributes',
|
||||
'onClickParams' => array('warning', $event['Event']['id'])
|
||||
'onClickParams' => array('warning', $eventId)
|
||||
);
|
||||
$data = array(
|
||||
'children' => array(
|
||||
|
@ -54,9 +55,8 @@
|
|||
'id' => 'create-button',
|
||||
'title' => $possibleAction === 'attribute' ? __('Add attribute') : __('Add proposal'),
|
||||
'fa-icon' => 'plus',
|
||||
'class' => 'last',
|
||||
'onClick' => 'openGenericModal',
|
||||
'onClickParams' => array('/' . $possibleAction . 's/add/' . h($event['Event']['id']))
|
||||
'class' => 'last modal-open',
|
||||
'url' => $baseurl . '/' . $possibleAction . 's/add/' . $eventId,
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-edit-button',
|
||||
|
@ -64,7 +64,7 @@
|
|||
'class' => 'mass-select hidden',
|
||||
'fa-icon' => 'edit',
|
||||
'onClick' => 'editSelectedAttributes',
|
||||
'onClickParams' => array($event['Event']['id'])
|
||||
'onClickParams' => array($eventId)
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-tag-button',
|
||||
|
@ -81,7 +81,7 @@
|
|||
'fa-icon' => 'rebel',
|
||||
'fa-source' => 'fab',
|
||||
'onClick' => 'popoverPopup',
|
||||
'onClickParams' => array('this', 'selected/attribute/eventid:' . h($event['Event']['id']), 'galaxies', 'selectGalaxyNamespace')
|
||||
'onClickParams' => array('this', 'selected/attribute/eventid:' . $eventId, 'galaxies', 'selectGalaxyNamespace')
|
||||
),
|
||||
array(
|
||||
'id' => 'group-into-object-button',
|
||||
|
@ -90,7 +90,7 @@
|
|||
'fa-icon' => 'object-group',
|
||||
'fa-source' => 'fa',
|
||||
'onClick' => 'proposeObjectsFromSelectedAttributes',
|
||||
'onClickParams' => array('this', $event['Event']['id'])
|
||||
'onClickParams' => array('this', $eventId)
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-delete-button',
|
||||
|
@ -98,7 +98,7 @@
|
|||
'class' => 'mass-select hidden',
|
||||
'fa-icon' => 'trash',
|
||||
'onClick' => 'multiSelectAction',
|
||||
'onClickParams' => array($event['Event']['id'], 'deleteAttributes')
|
||||
'onClickParams' => array($eventId, 'deleteAttributes')
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-accept-button',
|
||||
|
@ -106,7 +106,7 @@
|
|||
'class' => 'mass-proposal-select hidden',
|
||||
'fa-icon' => 'check-circle',
|
||||
'onClick' => 'multiSelectAction',
|
||||
'onClickParams' => array($event['Event']['id'], 'acceptProposals')
|
||||
'onClickParams' => array($eventId, 'acceptProposals')
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-discard-button',
|
||||
|
@ -114,7 +114,7 @@
|
|||
'class' => 'mass-proposal-select hidden',
|
||||
'fa-icon' => 'times',
|
||||
'onClick' => 'multiSelectAction',
|
||||
'onClickParams' => array($event['Event']['id'], 'discardProposals')
|
||||
'onClickParams' => array($eventId, 'discardProposals')
|
||||
),
|
||||
array(
|
||||
'id' => 'multi-sighting-button',
|
||||
|
@ -132,7 +132,7 @@
|
|||
'title' => __('Populate using a template'),
|
||||
'fa-icon' => 'list',
|
||||
'onClick' => 'getPopup',
|
||||
'onClickParams' => array($event['Event']['id'], 'templates', 'templateChoices'),
|
||||
'onClickParams' => array($eventId, 'templates', 'templateChoices'),
|
||||
'requirement' => $mayModify
|
||||
),
|
||||
array(
|
||||
|
@ -140,14 +140,14 @@
|
|||
'title' => __('Populate using the freetext import tool'),
|
||||
'fa-icon' => 'align-left',
|
||||
'onClick' => 'getPopup',
|
||||
'onClickParams' => array($event['Event']['id'], 'events', 'freeTextImport')
|
||||
'onClickParams' => array($eventId, 'events', 'freeTextImport')
|
||||
),
|
||||
array(
|
||||
'id' => 'attribute-replace-button',
|
||||
'title' => __('Replace all attributes of a category/type combination within the event'),
|
||||
'fa-icon' => 'random',
|
||||
'onClick' => 'getPopup',
|
||||
'onClickParams' => array($event['Event']['id'], 'attributes', 'attributeReplace'),
|
||||
'onClickParams' => array($eventId, 'attributes', 'attributeReplace'),
|
||||
'requirement' => $mayModify
|
||||
)
|
||||
)
|
||||
|
@ -236,7 +236,7 @@
|
|||
'fa-icon' => 'times',
|
||||
'title' => __('Remove filters'),
|
||||
'onClick' => 'filterAttributes',
|
||||
'onClickParams' => array('all', $event['Event']['id'])
|
||||
'onClickParams' => array('all', $eventId)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -114,13 +114,22 @@
|
|||
$action['onclick']
|
||||
);
|
||||
}
|
||||
$title = empty($action['title']) ? '' : h($action['title']);
|
||||
|
||||
$classes = [];
|
||||
if (!empty($action['class'])) {
|
||||
$classes[] = h($action['class']);
|
||||
}
|
||||
if (!empty($action['dbclickAction'])) {
|
||||
$classes[] = 'dblclickActionElement';
|
||||
}
|
||||
echo sprintf(
|
||||
'<a href="%s" title="%s" aria-label="%s" %s %s><i class="black %s"></i></a> ',
|
||||
'<a href="%s" title="%s" aria-label="%s"%s%s><i class="black %s"></i></a> ',
|
||||
$url,
|
||||
empty($action['title']) ? '' : h($action['title']),
|
||||
empty($action['title']) ? '' : h($action['title']),
|
||||
empty($action['dbclickAction']) ? '' : 'class="dblclickActionElement"',
|
||||
empty($action['onclick']) ? '' : sprintf('onclick="event.preventDefault();%s"', $action['onclick']),
|
||||
$title,
|
||||
$title,
|
||||
empty($classes) ? '' : ' class="' . implode(' ', $classes) . '"',
|
||||
empty($action['onclick']) ? '' : sprintf(' onclick="event.preventDefault();%s"', $action['onclick']),
|
||||
$this->FontAwesome->getClass($action['icon'])
|
||||
);
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
}
|
||||
$onClickParams = implode(',', $onClickParams);
|
||||
$onClick = sprintf(
|
||||
'onClick="%s%s"',
|
||||
'onclick="%s%s"',
|
||||
(empty($data['url'])) ? 'event.preventDefault();' : '',
|
||||
(!empty($data['onClick']) ? sprintf(
|
||||
'%s(%s)',
|
||||
|
@ -54,4 +54,3 @@
|
|||
empty($data['badge']) ? '' : sprintf('<span class="badge badge-%s">%s</span>', empty($data['badge']['type']) ? 'info' : $data['badge']['type'], h($data['badge']['text']))
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -27,26 +27,20 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
|
|||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardImport',
|
||||
'text' => __('Import Config JSON'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/import')
|
||||
),
|
||||
'url' => $baseurl . '/dashboards/import',
|
||||
'link_class' => 'modal-open',
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardExport',
|
||||
'text' => __('Export Config JSON'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/export')
|
||||
),
|
||||
'url' => $baseurl . '/dashboards/export',
|
||||
'link_class' => 'modal-open',
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardSave',
|
||||
'text' => __('Save Dashboard Config'),
|
||||
'onClick' => array(
|
||||
'function' => 'openGenericModal',
|
||||
'params' => array($baseurl . '/dashboards/saveTemplate')
|
||||
),
|
||||
'url' => $baseurl . '/dashboards/saveTemplate',
|
||||
'link_class' => 'modal-open',
|
||||
));
|
||||
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
|
||||
'element_id' => 'dashboardTemplateIndex',
|
||||
|
@ -55,7 +49,7 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
|
|||
));
|
||||
break;
|
||||
case 'event':
|
||||
$eventId = intval($event['Event']['id']);
|
||||
$eventId = (int)$event['Event']['id'];
|
||||
echo '<div id="hiddenSideMenuData" class="hidden" data-event-id="' . $eventId . '"></div>';
|
||||
if (in_array($menuItem, array('editEvent', 'addAttribute', 'addObject', 'addAttachment', 'addIOC', 'addThreatConnect', 'populateFromTemplate', 'merge'))) {
|
||||
// we can safely assume that mayModify is true if coming from these actions, as they require it in the controller and the user has already passed that check
|
||||
|
|
|
@ -29,6 +29,9 @@ if (empty($url)) {
|
|||
if (!empty($title)) {
|
||||
$a .= ' title="' . h($title) . '"';
|
||||
}
|
||||
if (!empty($link_class)) {
|
||||
$a .= ' class="' . h($link_class) . '"';
|
||||
}
|
||||
if (!empty($onClick)) {
|
||||
$params = '';
|
||||
foreach ($onClick['params'] as $param) {
|
||||
|
|
|
@ -12,6 +12,11 @@ if (!empty($field['url'])) {
|
|||
}
|
||||
foreach ($field['url_vars'] as $k => $path) {
|
||||
$field['url'] = str_replace('{{' . $k . '}}', Hash::extract($data, $path)[0], $field['url']);
|
||||
$temp = explode(':', $field['url']);
|
||||
if (!in_array(strtolower($temp[0]), ['http', 'https'])) {
|
||||
$field['url'] = '#';
|
||||
$string = 'Malformed URL - invalid protocol (' . h($temp[0]) . ':)';
|
||||
}
|
||||
}
|
||||
}
|
||||
$string = sprintf(
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
$event = Hash::extract($data, $field['event_path']);
|
||||
if ($event['protected']) {
|
||||
echo sprintf(
|
||||
'<span class="fas fa-lock"></span> %s %s %s <br />',
|
||||
'<span class="fas fa-lock"></span> %s %s %s <br>',
|
||||
__('Event is in protected mode. (Limited distribution)'),
|
||||
!$field['owner'] ? '' : sprintf(
|
||||
'<br /><a href="#" onClick="%s" title="%s"><i class="fas fa-unlock"></i> %s</a>',
|
||||
'<br><a href="%s" class="modal-open" title="%s"><i class="fas fa-unlock"></i> %s</a>',
|
||||
sprintf(
|
||||
"openGenericModal('%s/events/unprotect/%s');",
|
||||
'%s/events/unprotect/%s',
|
||||
$baseurl,
|
||||
h($event['id'])
|
||||
),
|
||||
|
@ -16,11 +16,10 @@
|
|||
empty($field['text']) ? __('Switch to unprotected mode') : h($field['text'])
|
||||
),
|
||||
!$field['owner'] ? '' : sprintf(
|
||||
'<br /><a href="#" onClick="%s"><i class="fas fa-key"></i>%s</a>',
|
||||
'<br><a href="%s" class="modal-open"><i class="fas fa-key"></i> %s</a>',
|
||||
sprintf(
|
||||
"openGenericModal('%s/CryptographicKeys/add/%s/%s');",
|
||||
"%s/CryptographicKeys/add/Event/%s",
|
||||
$baseurl,
|
||||
h('Event'),
|
||||
h($event['id'])
|
||||
),
|
||||
empty($field['text']) ? __('Add signing key') : h($field['text'])
|
||||
|
@ -33,7 +32,7 @@
|
|||
$foundInstanceKey = true;
|
||||
}
|
||||
echo sprintf(
|
||||
'%s<span class="bold">%s</span> (%s) <a href="#" onClick="%s" title="%s"><i class="fas fa-search"></i></a> %s<br />',
|
||||
'%s<span class="bold">%s</span> (%s) <a href="%s" class="modal-open" title="%s"><i class="fas fa-search"></i></a> %s<br>',
|
||||
!$isInstanceKey ? '' : sprintf(
|
||||
'<i class="fas fa-home blue" title="%s"></i> ',
|
||||
__('This is the instance signing key. When synchronising the instance, this will be the key used to validate the event.')
|
||||
|
@ -41,13 +40,13 @@
|
|||
h($key['type']),
|
||||
empty($key['fingerprint']) ? '#' . h($key['id']) : h($key['fingerprint']),
|
||||
sprintf(
|
||||
"openGenericModal('%s/cryptographicKeys/view/%s');",
|
||||
"%s/cryptographicKeys/view/%s",
|
||||
$baseurl,
|
||||
h($key['id'])
|
||||
),
|
||||
__('Inspect key'),
|
||||
!$field['owner'] ? '' : sprintf(
|
||||
'<a href="#" onClick="openGenericModal(\'%s/cryptographicKeys/delete/%s\')" title="%s"><i class="fas fa-trash"></i></a>',
|
||||
'<a href="%s/cryptographicKeys/delete/%s" class="modal-open" title="%s"><i class="fas fa-trash"></i></a>',
|
||||
$baseurl,
|
||||
h($key['id']),
|
||||
__('Detach key from the event. This key will no longer be used to sign and validate this event.')
|
||||
|
@ -64,12 +63,12 @@
|
|||
}
|
||||
} else {
|
||||
echo sprintf(
|
||||
'<span class="fas fa-unlock"></span> <span>%s</span> %s<br />',
|
||||
'<span class="fas fa-unlock"></span> <span>%s</span> %s<br>',
|
||||
__('Event is in unprotected mode.'),
|
||||
!$field['owner'] ? '' : sprintf(
|
||||
'<br /><a href="#" onClick="%s" title="%s"><i class="fas fa-lock"></i> %s</a>',
|
||||
'<br><a href="%s" class="modal-open" title="%s"><i class="fas fa-lock"></i> %s</a>',
|
||||
sprintf(
|
||||
"openGenericModal('%s/events/protect/%s');",
|
||||
"%s/events/protect/%s",
|
||||
$baseurl,
|
||||
h($event['id'])
|
||||
),
|
||||
|
@ -78,4 +77,3 @@
|
|||
)
|
||||
);
|
||||
}
|
||||
//echo ;
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
);
|
||||
}
|
||||
}
|
||||
$ajaxLists = '<br/>';
|
||||
$ajaxLists = '<br>';
|
||||
if (!empty($children)) {
|
||||
foreach ($children as $child) {
|
||||
$ajaxLists .= $this->element(
|
||||
|
@ -131,4 +131,4 @@
|
|||
$appendHtml,
|
||||
$ajax ? '' : $this->element('/genericElements/SideMenu/side_menu', $menuData)
|
||||
);
|
||||
?>
|
||||
|
||||
|
|
|
@ -544,7 +544,7 @@
|
|||
);
|
||||
}
|
||||
?>
|
||||
<div id="topBar" class="navbar navbar-inverse <?= $debugMode ?>">
|
||||
<div id="topBar" class="navbar navbar-inverse <?= isset($debugMode) ? $debugMode : 'debugOff' ?>">
|
||||
<div class="navbar-inner">
|
||||
<ul class="nav">
|
||||
<?php
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
<?php
|
||||
$showLinebreak = in_array($responseType, ['txt', 'xml']);
|
||||
?>
|
||||
<div class="index">
|
||||
<div id="restSearchExportResult">
|
||||
<?php
|
||||
if (!empty($renderView)) {
|
||||
echo $this->render('/Events/module_views/' . $renderView, false);
|
||||
}
|
||||
?>
|
||||
<div id="restSearchExportResult" style="<?= $showLinebreak ? 'white-space: pre;' : '' ?>">
|
||||
<?php
|
||||
if (!empty($renderView)) {
|
||||
echo $this->render('/Events/module_views/' . $renderView, false);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
[
|
||||
'key' => __('Contributors'),
|
||||
'type' => 'custom',
|
||||
'function' => function ($data) use($contributors, $baseurl, $event) {
|
||||
'function' => function ($data) use ($contributors, $baseurl, $event) {
|
||||
$contributorsContent = [];
|
||||
foreach ($contributors as $organisationId => $name) {
|
||||
$org = ['Organisation' => ['id' => $organisationId, 'name' => $name]];
|
||||
|
@ -243,7 +243,7 @@
|
|||
'key' => __('Delegation request'),
|
||||
'class' => 'background-red bold',
|
||||
'type' => 'delegationRequest',
|
||||
'delegationRequest' => $delegationRequest,
|
||||
'delegationRequest' => isset($delegationRequest) ? $delegationRequest : null,
|
||||
'requirement' => !empty($delegationRequest)
|
||||
],
|
||||
[
|
||||
|
@ -254,7 +254,7 @@
|
|||
return sprintf(
|
||||
'%s%s',
|
||||
$data['Event']['disable_correlation'] ? __('Disabled') : __('Enabled'),
|
||||
(!$mayModify && !$isSiteAdmin) ? '' : sprintf(
|
||||
(!$mayModify && !$isSiteAdmin) ? '' :
|
||||
sprintf(
|
||||
' (<a onClick="getPopup(%s);" style="%scursor:pointer;font-weight:normal;">%s</a>)',
|
||||
sprintf(
|
||||
|
@ -264,7 +264,6 @@
|
|||
$data['Event']['disable_correlation'] ? 'color:white;' : '',
|
||||
$data['Event']['disable_correlation'] ? __('enable') : __('disable')
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
'requirement' => (!Configure::read('MISP.completely_disable_correlation') && Configure::read('MISP.allow_disabling_correlation'))
|
||||
|
@ -302,4 +301,3 @@
|
|||
]
|
||||
]
|
||||
);
|
||||
?>
|
||||
|
|
|
@ -56,7 +56,7 @@ $table_data[] = array('key' => __('Collection UUID'), 'value' => $cluster['Galax
|
|||
$table_data[] = array(
|
||||
'key' => __('Source'),
|
||||
'html' => filter_var($cluster['GalaxyCluster']['source'], FILTER_VALIDATE_URL) ?
|
||||
'<a href="' . $cluster['GalaxyCluster']['source'] . '" rel="noreferrer noopener">' . h($cluster['GalaxyCluster']['source']) :
|
||||
'<a href="' . h($cluster['GalaxyCluster']['source']) . '" rel="noreferrer noopener">' . h($cluster['GalaxyCluster']['source']) :
|
||||
h($cluster['GalaxyCluster']['source']),
|
||||
);
|
||||
$table_data[] = array('key' => __('Authors'), 'value' => !empty($cluster['GalaxyCluster']['authors']) ? implode(', ', $cluster['GalaxyCluster']['authors']) : __('N/A'));
|
||||
|
|
|
@ -50,7 +50,7 @@ echo $this->element('genericElements/Form/genericForm', [
|
|||
'type' => 'file',
|
||||
'field' => 'logo',
|
||||
'error' => array('escape' => false),
|
||||
'label' => __('Logo (48×48 PNG or SVG)'),
|
||||
'label' => __('Logo (48×48 %s)', Configure::read('Security.enable_svg_logos')? 'PNG or SVG' : 'PNG'),
|
||||
],
|
||||
[
|
||||
'field' => 'nationality',
|
||||
|
|
|
@ -84,18 +84,16 @@ if ($isSiteAdmin) {
|
|||
$actions = [
|
||||
[
|
||||
'url' => $baseurl . '/admin/roles/edit',
|
||||
'url_params_data_paths' => array(
|
||||
'Role.id'
|
||||
),
|
||||
'url_params_data_paths' => ['Role.id'],
|
||||
'icon' => 'edit',
|
||||
'title' => __('Edit role'),
|
||||
],
|
||||
[
|
||||
'onclick' => sprintf(
|
||||
'openGenericModal(\'%s/admin/roles/delete/[onclick_params_data_path]\');',
|
||||
$baseurl
|
||||
),
|
||||
'onclick_params_data_path' => 'Role.id',
|
||||
'class' => 'modal-open',
|
||||
'url' => "$baseurl/admin/roles/delete",
|
||||
'url_params_data_paths' => ['Role.id'],
|
||||
'icon' => 'trash',
|
||||
'title' => __('Delete role'),
|
||||
]
|
||||
];
|
||||
} else {
|
||||
|
@ -116,14 +114,8 @@ echo $this->element('genericElements/IndexTable/scaffold', [
|
|||
'type' => 'simple',
|
||||
'text' => __('Add role'),
|
||||
'fa-icon' => 'plus',
|
||||
'class' => 'btn btn-primary',
|
||||
'onClick' => 'openGenericModal',
|
||||
'onClickParams' => [
|
||||
sprintf(
|
||||
'%s/admin/roles/add',
|
||||
$baseurl
|
||||
)
|
||||
],
|
||||
'class' => 'btn-primary modal-open',
|
||||
'url' => "$baseurl/admin/roles/add",
|
||||
'requirement' => $isSiteAdmin,
|
||||
]
|
||||
]
|
||||
|
|
|
@ -39,13 +39,13 @@
|
|||
<?php
|
||||
echo $this->Form->input('email', array('autocomplete' => 'off', 'autofocus'));
|
||||
echo $this->Form->input('password', array('autocomplete' => 'off'));
|
||||
if (!empty(Configure::read('LinOTPAuth'))) {
|
||||
if (!empty(Configure::read('LinOTPAuth')) && Configure::read('LinOTPAuth.enabled')!== FALSE) {
|
||||
echo $this->Form->input('otp', array('autocomplete' => 'off', 'type' => 'password', 'label' => 'OTP'));
|
||||
echo "<div class=\"clear\">";
|
||||
echo sprintf(
|
||||
'%s <a href="%s/selfservice" title="LinOTP Selfservice">LinOTP Selfservice</a> %s',
|
||||
__('Visit'),
|
||||
Configure::read('LinOTPAuth.baseUrl'),
|
||||
h(Configure::read('LinOTPAuth.baseUrl')),
|
||||
__('for the One-Time-Password selfservice.')
|
||||
);
|
||||
}
|
||||
|
@ -92,7 +92,10 @@ function submitLoginForm() {
|
|||
var url = $form.attr('action')
|
||||
var email = $form.find('#UserEmail').val()
|
||||
var password = $form.find('#UserPassword').val()
|
||||
if (!empty(Configure::read('LinOTPAuth'))) {
|
||||
var LinOTPAuth = <?= empty(Configure::read('LinOTPAuth')) ? 'false' : 'true' ?>;
|
||||
var LinOTPAuthEnabled = <?= empty(Configure::read('LinOTPAuth.enabled')) ? 'false' : 'true' ?>;
|
||||
|
||||
if (LinOTPAuth && LinOTPAuthEnabled) {
|
||||
var otp = $form.find('#UserOtp').val()
|
||||
}
|
||||
if (!$form[0].checkValidity()) {
|
||||
|
@ -107,7 +110,7 @@ function submitLoginForm() {
|
|||
var $tmpForm = $('#temp form#UserLoginForm')
|
||||
$tmpForm.find('#UserEmail').val(email)
|
||||
$tmpForm.find('#UserPassword').val(password)
|
||||
if (!empty(Configure::read('LinOTPAuth'))) {
|
||||
if (LinOTPAuth && LinOTPAuthEnabled) {
|
||||
$tmpForm.find('#UserOtp').val(otp)
|
||||
}
|
||||
$tmpForm.submit()
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
if (!Configure::read('MISP.terms_file')) {
|
||||
$termsFile = APP ."View/Users/terms";
|
||||
} else {
|
||||
$termsFile = APP . 'files' . DS . 'terms' . DS . Configure::read('MISP.terms_file');
|
||||
$customTermsFile = basename(realpath(Configure::read('MISP.terms_file')));
|
||||
$termsFile = APP . 'files' . DS . 'terms' . DS . $customTermsFile;
|
||||
}
|
||||
if (!(file_exists($termsFile))) {
|
||||
echo "<p>" . __("Terms and Conditions file not found.") . "</p>";
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f49b54281b7645b703663a99613f6909ebc7a989
|
||||
Subproject commit 4242732af18c873e192a8450bac466bd59742b91
|
|
@ -1 +1 @@
|
|||
Subproject commit 9515ae332e45d9ac306eaaaa802b605c1090cf5c
|
||||
Subproject commit ea23d591851856098fe8a7333823f5ebeda545d4
|
|
@ -1 +1 @@
|
|||
Subproject commit 6da2a75fc41afb401d5c16635dfcd48d43372a88
|
||||
Subproject commit 92d74aa5fc76080ddfd6cbaa7bdce18e30d11634
|
|
@ -1 +1 @@
|
|||
Subproject commit 653a035ae77fa46e9f6b1608b9f75bd1506bd1a6
|
||||
Subproject commit a6da32235f04b4c26fe9d1478bf385410232c872
|
|
@ -1,371 +1,371 @@
|
|||
class ActionTable {
|
||||
constructor(options) {
|
||||
this.__globalCounter = 0;
|
||||
this.options = options;
|
||||
this.id = options.id;
|
||||
this.container = options.container;
|
||||
this.classes = options.classes;
|
||||
this.table_title = options.title;
|
||||
this.header = options.header;
|
||||
this.onAddition = options.onAddition;
|
||||
this.onRemove = options.onRemove;
|
||||
this.header.push("Action");
|
||||
this.row_num = this.header.length;
|
||||
this.data = options.data === undefined ? [] : options.data;
|
||||
this.tr_id_mapping = {};
|
||||
this.control_items = options.control_items;
|
||||
this.header_action_button = options.header_action_button === undefined ? {} : options.header_action_button;
|
||||
if (options.header_action_button !== undefined) {
|
||||
this.header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
|
||||
this.additionEnabled = this.header_action_button.additionEnabled === undefined ? true : this.header_action_button.additionEnabled;
|
||||
this.additionButtonDisabled = this.header_action_button.disabled === undefined ? false : this.header_action_button.disabled;
|
||||
} else {
|
||||
this.header_action_button_style = {};
|
||||
this.additionEnabled = true;
|
||||
this.additionButtonDisabled = false;
|
||||
}
|
||||
constructor(options) {
|
||||
this.__globalCounter = 0;
|
||||
this.options = options;
|
||||
this.id = options.id;
|
||||
this.container = options.container;
|
||||
this.classes = options.classes;
|
||||
this.table_title = options.title;
|
||||
this.header = options.header;
|
||||
this.onAddition = options.onAddition;
|
||||
this.onRemove = options.onRemove;
|
||||
this.header.push("Action");
|
||||
this.row_num = this.header.length;
|
||||
this.data = options.data === undefined ? [] : options.data;
|
||||
this.tr_id_mapping = {};
|
||||
this.control_items = options.control_items;
|
||||
this.header_action_button = options.header_action_button === undefined ? {} : options.header_action_button;
|
||||
if (options.header_action_button !== undefined) {
|
||||
this.header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
|
||||
this.additionEnabled = this.header_action_button.additionEnabled === undefined ? true : this.header_action_button.additionEnabled;
|
||||
this.additionButtonDisabled = this.header_action_button.disabled === undefined ? false : this.header_action_button.disabled;
|
||||
} else {
|
||||
this.header_action_button_style = {};
|
||||
this.additionEnabled = true;
|
||||
this.additionButtonDisabled = false;
|
||||
}
|
||||
|
||||
this.row_action_button = options.row_action_button === undefined ? {} : options.row_action_button;
|
||||
if (options.row_action_button !== undefined) {
|
||||
this.row_action_button_style = this.row_action_button.style === undefined ? {} : this.row_action_button.style;
|
||||
this.removalEnabled = this.row_action_button.removalEnabled === undefined ? true : this.row_action_button.removalEnabled;
|
||||
} else {
|
||||
this.row_action_button_style = {};
|
||||
this.removalEnabled = true;
|
||||
}
|
||||
this.row_action_button = options.row_action_button === undefined ? {} : options.row_action_button;
|
||||
if (options.row_action_button !== undefined) {
|
||||
this.row_action_button_style = this.row_action_button.style === undefined ? {} : this.row_action_button.style;
|
||||
this.removalEnabled = this.row_action_button.removalEnabled === undefined ? true : this.row_action_button.removalEnabled;
|
||||
} else {
|
||||
this.row_action_button_style = {};
|
||||
this.removalEnabled = true;
|
||||
}
|
||||
|
||||
this.selects = {};
|
||||
this.selects = {};
|
||||
|
||||
this.__create_table();
|
||||
}
|
||||
this.__create_table();
|
||||
}
|
||||
|
||||
__get_uniq_index() {
|
||||
this.__globalCounter++;
|
||||
return this.__globalCounter-1;
|
||||
}
|
||||
__get_uniq_index() {
|
||||
this.__globalCounter++;
|
||||
return this.__globalCounter-1;
|
||||
}
|
||||
|
||||
add_row(row) {
|
||||
if (!this.__data_already_exists(row)) {
|
||||
var id = this.__add_row(row);
|
||||
this.tr_id_mapping[this.data.length] = id;
|
||||
this.data.push(row);
|
||||
}
|
||||
}
|
||||
add_row(row) {
|
||||
if (!this.__data_already_exists(row)) {
|
||||
var id = this.__add_row(row);
|
||||
this.tr_id_mapping[this.data.length] = id;
|
||||
this.data.push(row);
|
||||
}
|
||||
}
|
||||
|
||||
delete_row(row_id) {
|
||||
var tr = document.getElementById(row_id);
|
||||
var array = this.__get_array_from_DOM_row(tr);
|
||||
var data_index = this.__find_array_index(array, this.data);
|
||||
tr.outerHTML = "";
|
||||
this.data.splice(data_index, 1);
|
||||
}
|
||||
delete_row(row_id) {
|
||||
var tr = document.getElementById(row_id);
|
||||
var array = this.__get_array_from_DOM_row(tr);
|
||||
var data_index = this.__find_array_index(array, this.data);
|
||||
tr.outerHTML = "";
|
||||
this.data.splice(data_index, 1);
|
||||
}
|
||||
|
||||
delete_row_index(row_pos) {
|
||||
var tr = this.get_DOM_row(row_pos);
|
||||
var array = this.__get_array_from_DOM_row(tr);
|
||||
var data_index = this.__find_array_index(array, this.data);
|
||||
tr.outerHTML = "";
|
||||
this.data.splice(data_index, 1);
|
||||
}
|
||||
delete_row_index(row_pos) {
|
||||
var tr = this.get_DOM_row(row_pos);
|
||||
var array = this.__get_array_from_DOM_row(tr);
|
||||
var data_index = this.__find_array_index(array, this.data);
|
||||
tr.outerHTML = "";
|
||||
this.data.splice(data_index, 1);
|
||||
}
|
||||
|
||||
get_DOM_row(row_pos) {
|
||||
var row_id = this.tr_id_mapping[row_pos];
|
||||
var tr = document.getElementById(row_id);
|
||||
return tr;
|
||||
}
|
||||
get_DOM_row(row_pos) {
|
||||
var row_id = this.tr_id_mapping[row_pos];
|
||||
var tr = document.getElementById(row_id);
|
||||
return tr;
|
||||
}
|
||||
|
||||
get_data() {
|
||||
return this.data;
|
||||
}
|
||||
get_data() {
|
||||
return this.data;
|
||||
}
|
||||
|
||||
clear_table() {
|
||||
var dataLength = this.data.length;
|
||||
for (var i=0; i<dataLength; i++) {
|
||||
this.delete_row_index(i);
|
||||
}
|
||||
}
|
||||
clear_table() {
|
||||
var dataLength = this.data.length;
|
||||
for (var i=0; i<dataLength; i++) {
|
||||
this.delete_row_index(i);
|
||||
}
|
||||
}
|
||||
|
||||
set_table_data(data) {
|
||||
this.clear_table();
|
||||
for (var i in data) {
|
||||
this.add_row(data[i]);
|
||||
}
|
||||
}
|
||||
set_table_data(data) {
|
||||
this.clear_table();
|
||||
for (var i in data) {
|
||||
this.add_row(data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
add_options(id, values) {
|
||||
var select = this.selects[id];
|
||||
var selected_value = select.value;
|
||||
select.innerHTML = ""; // ensure uniqueness
|
||||
this.__add_options_to_select(select, values);
|
||||
select.value = selected_value;
|
||||
}
|
||||
add_options(id, values) {
|
||||
var select = this.selects[id];
|
||||
var selected_value = select.value;
|
||||
select.innerHTML = ""; // ensure uniqueness
|
||||
this.__add_options_to_select(select, values);
|
||||
select.value = selected_value;
|
||||
}
|
||||
|
||||
__get_array_from_DOM_row(tr) {
|
||||
var children = tr.children;
|
||||
var array = [];
|
||||
for (var i = 0; i < children.length-1; i++) {
|
||||
array.push(children[i].innerText);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
__get_array_from_DOM_row(tr) {
|
||||
var children = tr.children;
|
||||
var array = [];
|
||||
for (var i = 0; i < children.length-1; i++) {
|
||||
array.push(children[i].innerText);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
__data_already_exists(data) {
|
||||
return this.__find_array_index(data, this.data) >= 0;
|
||||
}
|
||||
__data_already_exists(data) {
|
||||
return this.__find_array_index(data, this.data) >= 0;
|
||||
}
|
||||
|
||||
__find_array_index(value, array) {
|
||||
for (var i in array) {
|
||||
if (JSON.stringify(array[i]) === JSON.stringify(value)) { // compare array
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
__find_array_index(value, array) {
|
||||
for (var i in array) {
|
||||
if (JSON.stringify(array[i]) === JSON.stringify(value)) { // compare array
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
__create_table() {
|
||||
if (this.table_title !== undefined) {
|
||||
var label = document.createElement('label');
|
||||
label.innerHTML = this.table_title;
|
||||
this.container.appendChild(label);
|
||||
}
|
||||
this.form = document.createElement('form');
|
||||
this.table = document.createElement('table');
|
||||
this.table.classList.add("table", "table-bordered", "action-table");
|
||||
if (this.classes !== undefined) {
|
||||
for (var i in this.classes) {
|
||||
this.table.classList.add(this.classes[i]);
|
||||
}
|
||||
}
|
||||
this.thead = document.createElement('thead');
|
||||
this.tbody = document.createElement('tbody');
|
||||
var trHead = document.createElement('tr');
|
||||
for (var col of this.header) {
|
||||
var th = document.createElement('th');
|
||||
th.innerHTML = col;
|
||||
trHead.appendChild(th);
|
||||
}
|
||||
this.thead.appendChild(trHead);
|
||||
__create_table() {
|
||||
if (this.table_title !== undefined) {
|
||||
var label = document.createElement('label');
|
||||
label.innerHTML = this.table_title;
|
||||
this.container.appendChild(label);
|
||||
}
|
||||
this.form = document.createElement('form');
|
||||
this.table = document.createElement('table');
|
||||
this.table.classList.add("table", "table-bordered", "action-table");
|
||||
if (this.classes !== undefined) {
|
||||
for (var i in this.classes) {
|
||||
this.table.classList.add(this.classes[i]);
|
||||
}
|
||||
}
|
||||
this.thead = document.createElement('thead');
|
||||
this.tbody = document.createElement('tbody');
|
||||
var trHead = document.createElement('tr');
|
||||
for (var col of this.header) {
|
||||
var th = document.createElement('th');
|
||||
th.innerHTML = col;
|
||||
trHead.appendChild(th);
|
||||
}
|
||||
this.thead.appendChild(trHead);
|
||||
|
||||
this.__add_control_row();
|
||||
this.__add_control_row();
|
||||
|
||||
for (var row of this.data) {
|
||||
this.__add_row(row);
|
||||
}
|
||||
this.table.appendChild(this.thead);
|
||||
this.table.appendChild(this.tbody);
|
||||
this.form.appendChild(this.table);
|
||||
this.container.appendChild(this.form);
|
||||
}
|
||||
for (var row of this.data) {
|
||||
this.__add_row(row);
|
||||
}
|
||||
this.table.appendChild(this.thead);
|
||||
this.table.appendChild(this.tbody);
|
||||
this.form.appendChild(this.table);
|
||||
this.container.appendChild(this.form);
|
||||
}
|
||||
|
||||
__add_row(row) {
|
||||
var tr = document.createElement('tr');
|
||||
tr.id = "tr_" + this.__uuidv4();
|
||||
for (var col of row) {
|
||||
var td = document.createElement('td');
|
||||
td.innerHTML = col;
|
||||
tr.appendChild(td);
|
||||
}
|
||||
this.__add_action_button(tr);
|
||||
this.tbody.appendChild(tr);
|
||||
return tr.id;
|
||||
}
|
||||
__add_row(row) {
|
||||
var tr = document.createElement('tr');
|
||||
tr.id = "tr_" + this.__uuidv4();
|
||||
for (var col of row) {
|
||||
var td = document.createElement('td');
|
||||
td.innerHTML = col;
|
||||
tr.appendChild(td);
|
||||
}
|
||||
this.__add_action_button(tr);
|
||||
this.tbody.appendChild(tr);
|
||||
return tr.id;
|
||||
}
|
||||
|
||||
__add_control_row() {
|
||||
var tr = document.createElement('tr');
|
||||
for (var itemOption of this.control_items) {
|
||||
var td = document.createElement('td');
|
||||
var item = this.__add_control_item(itemOption);
|
||||
if (itemOption.colspan !== undefined) {
|
||||
td.colSpan = itemOption.colspan;
|
||||
}
|
||||
td.appendChild(item);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
var td = document.createElement('td');
|
||||
__add_control_row() {
|
||||
var tr = document.createElement('tr');
|
||||
for (var itemOption of this.control_items) {
|
||||
var td = document.createElement('td');
|
||||
var item = this.__add_control_item(itemOption);
|
||||
if (itemOption.colspan !== undefined) {
|
||||
td.colSpan = itemOption.colspan;
|
||||
}
|
||||
td.appendChild(item);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
var td = document.createElement('td');
|
||||
|
||||
var btn = document.createElement('button');
|
||||
var header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
|
||||
if (header_action_button_style.type !== undefined) {
|
||||
btn.classList.add("btn", "btn-"+header_action_button_style.type);
|
||||
} else {
|
||||
btn.classList.add("btn", "btn-primary");
|
||||
}
|
||||
if (header_action_button_style.tooltip !== undefined) {
|
||||
btn.title = header_action_button_style.tooltip;
|
||||
}
|
||||
if (header_action_button_style.icon !== undefined) {
|
||||
btn.innerHTML = '<span class="fa '+header_action_button_style.icon+'"></span>';
|
||||
} else {
|
||||
btn.innerHTML = '<span class="fa fa-plus-square"></span>';
|
||||
}
|
||||
btn.type = "button";
|
||||
btn.disabled = this.additionButtonDisabled;
|
||||
var btn = document.createElement('button');
|
||||
var header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
|
||||
if (header_action_button_style.type !== undefined) {
|
||||
btn.classList.add("btn", "btn-"+header_action_button_style.type);
|
||||
} else {
|
||||
btn.classList.add("btn", "btn-primary");
|
||||
}
|
||||
if (header_action_button_style.tooltip !== undefined) {
|
||||
btn.title = header_action_button_style.tooltip;
|
||||
}
|
||||
if (header_action_button_style.icon !== undefined) {
|
||||
btn.innerHTML = '<span class="fa '+header_action_button_style.icon+'"></span>';
|
||||
} else {
|
||||
btn.innerHTML = '<span class="fa fa-plus-square"></span>';
|
||||
}
|
||||
btn.type = "button";
|
||||
btn.disabled = this.additionButtonDisabled;
|
||||
|
||||
var that = this;
|
||||
btn.addEventListener("click", function(evt) {
|
||||
var data = [];
|
||||
for (var elem of that.form.elements) {
|
||||
if (elem.classList.contains('form-group')) {
|
||||
data.push(elem.value);
|
||||
}
|
||||
}
|
||||
if (that.additionEnabled) {
|
||||
that.add_row(data);
|
||||
}
|
||||
if (that.onAddition !== undefined) {
|
||||
that.onAddition(data, that);
|
||||
}
|
||||
});
|
||||
var that = this;
|
||||
btn.addEventListener("click", function(evt) {
|
||||
var data = [];
|
||||
for (var elem of that.form.elements) {
|
||||
if (elem.classList.contains('form-group')) {
|
||||
data.push(elem.value);
|
||||
}
|
||||
}
|
||||
if (that.additionEnabled) {
|
||||
that.add_row(data);
|
||||
}
|
||||
if (that.onAddition !== undefined) {
|
||||
that.onAddition(data, that);
|
||||
}
|
||||
});
|
||||
|
||||
td.appendChild(btn);
|
||||
td.appendChild(btn);
|
||||
|
||||
tr.appendChild(td);
|
||||
this.thead.appendChild(tr);
|
||||
}
|
||||
tr.appendChild(td);
|
||||
this.thead.appendChild(tr);
|
||||
}
|
||||
|
||||
__add_control_item(options) {
|
||||
var item;
|
||||
switch(options.DOMType) {
|
||||
case "select":
|
||||
item = this.__create_select(options.item_options);
|
||||
this.selects[item.id] = item;
|
||||
break;
|
||||
case "input":
|
||||
item = this.__create_input(options.item_options);
|
||||
break;
|
||||
case "empty":
|
||||
item = this.__create_empty(options.item_options);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
__add_control_item(options) {
|
||||
var item;
|
||||
switch(options.DOMType) {
|
||||
case "select":
|
||||
item = this.__create_select(options.item_options);
|
||||
this.selects[item.id] = item;
|
||||
break;
|
||||
case "input":
|
||||
item = this.__create_input(options.item_options);
|
||||
break;
|
||||
case "empty":
|
||||
item = this.__create_empty(options.item_options);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
__add_action_button(tr) {
|
||||
var that = this;
|
||||
var td = document.createElement('td');
|
||||
var btn = document.createElement('button');
|
||||
btn.classList.add("btn", "btn-danger");
|
||||
btn.innerHTML = '<span class="fa fa-trash"></span>';
|
||||
btn.type = "button";
|
||||
btn.setAttribute('rowID', tr.id);
|
||||
if (that.row_action_button_style.tooltip !== undefined) {
|
||||
btn.title = that.row_action_button_style.tooltip;
|
||||
}
|
||||
if (that.row_action_button_style.style !== undefined) {
|
||||
btn.style = that.row_action_button_style.style;
|
||||
}
|
||||
var that = this;
|
||||
btn.addEventListener("click", function(evt) {
|
||||
if (that.onRemove !== undefined) {
|
||||
var tr = document.getElementById(this.getAttribute('rowID'));
|
||||
var data = that.__get_array_from_DOM_row(tr);
|
||||
that.onRemove(data, that);
|
||||
}
|
||||
if (that.removalEnabled) {
|
||||
that.delete_row(this.getAttribute('rowID'));
|
||||
}
|
||||
});
|
||||
td.appendChild(btn);
|
||||
__add_action_button(tr) {
|
||||
var that = this;
|
||||
var td = document.createElement('td');
|
||||
var btn = document.createElement('button');
|
||||
btn.classList.add("btn", "btn-danger");
|
||||
btn.innerHTML = '<span class="fa fa-trash"></span>';
|
||||
btn.type = "button";
|
||||
btn.setAttribute('rowID', tr.id);
|
||||
if (that.row_action_button_style.tooltip !== undefined) {
|
||||
btn.title = that.row_action_button_style.tooltip;
|
||||
}
|
||||
if (that.row_action_button_style.style !== undefined) {
|
||||
btn.style = that.row_action_button_style.style;
|
||||
}
|
||||
var that = this;
|
||||
btn.addEventListener("click", function(evt) {
|
||||
if (that.onRemove !== undefined) {
|
||||
var tr = document.getElementById(this.getAttribute('rowID'));
|
||||
var data = that.__get_array_from_DOM_row(tr);
|
||||
that.onRemove(data, that);
|
||||
}
|
||||
if (that.removalEnabled) {
|
||||
that.delete_row(this.getAttribute('rowID'));
|
||||
}
|
||||
});
|
||||
td.appendChild(btn);
|
||||
|
||||
if (that.row_action_button.others !== undefined) {
|
||||
for (var i in that.row_action_button.others) {
|
||||
var newBtnOptions = that.row_action_button.others[i];
|
||||
if (that.row_action_button.others !== undefined) {
|
||||
for (var i in that.row_action_button.others) {
|
||||
var newBtnOptions = that.row_action_button.others[i];
|
||||
|
||||
var btn_style = newBtnOptions.style !== undefined ? newBtnOptions.style : {};
|
||||
var btn = document.createElement('button');
|
||||
btn.type = "button";
|
||||
if (btn_style.type !== undefined) {
|
||||
btn.classList.add("btn", "btn-"+btn_style.type);
|
||||
} else {
|
||||
btn.classList.add("btn", "btn-primary");
|
||||
}
|
||||
if (btn_style.icon !== undefined) {
|
||||
btn.innerHTML = '<span class="fa '+btn_style.icon+'"></span>';
|
||||
} else {
|
||||
btn.innerHTML = '<span class="fa fa-check"></span>';
|
||||
}
|
||||
if (btn_style.title !== undefined) {
|
||||
btn.title = btn_style.title;
|
||||
}
|
||||
if (btn_style.style !== undefined) {
|
||||
btn.style = btn_style.style+"margin-left: 3px";
|
||||
} else {
|
||||
btn.style = "margin-left: 3px";
|
||||
}
|
||||
btn.setAttribute('rowID', tr.id);
|
||||
if (newBtnOptions.event !== undefined) {
|
||||
btn.addEventListener("click", function(evt) {
|
||||
var tr = document.getElementById(this.getAttribute('rowID'));
|
||||
var data = that.__get_array_from_DOM_row(tr);
|
||||
newBtnOptions.event(data, that);
|
||||
});
|
||||
}
|
||||
td.appendChild(btn);
|
||||
}
|
||||
}
|
||||
var btn_style = newBtnOptions.style !== undefined ? newBtnOptions.style : {};
|
||||
var btn = document.createElement('button');
|
||||
btn.type = "button";
|
||||
if (btn_style.type !== undefined) {
|
||||
btn.classList.add("btn", "btn-"+btn_style.type);
|
||||
} else {
|
||||
btn.classList.add("btn", "btn-primary");
|
||||
}
|
||||
if (btn_style.icon !== undefined) {
|
||||
btn.innerHTML = '<span class="fa '+btn_style.icon+'"></span>';
|
||||
} else {
|
||||
btn.innerHTML = '<span class="fa fa-check"></span>';
|
||||
}
|
||||
if (btn_style.title !== undefined) {
|
||||
btn.title = btn_style.title;
|
||||
}
|
||||
if (btn_style.style !== undefined) {
|
||||
btn.style = btn_style.style+"margin-left: 3px";
|
||||
} else {
|
||||
btn.style = "margin-left: 3px";
|
||||
}
|
||||
btn.setAttribute('rowID', tr.id);
|
||||
if (newBtnOptions.event !== undefined) {
|
||||
btn.addEventListener("click", function(evt) {
|
||||
var tr = document.getElementById(this.getAttribute('rowID'));
|
||||
var data = that.__get_array_from_DOM_row(tr);
|
||||
newBtnOptions.event(data, that);
|
||||
});
|
||||
}
|
||||
td.appendChild(btn);
|
||||
}
|
||||
}
|
||||
|
||||
tr.appendChild(td);
|
||||
}
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
__create_empty(options) {
|
||||
var empty = document.createElement('span');
|
||||
empty.classList.add("form-group");
|
||||
empty.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
return empty;
|
||||
}
|
||||
__create_empty(options) {
|
||||
var empty = document.createElement('span');
|
||||
empty.classList.add("form-group");
|
||||
empty.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
return empty;
|
||||
}
|
||||
|
||||
__create_input(options) {
|
||||
var input = document.createElement('input');
|
||||
input.classList.add("form-group");
|
||||
input.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
if (options.style !== undefined) {
|
||||
input.style = options.style;
|
||||
}
|
||||
if (options.placeholder !== undefined) {
|
||||
input.placeholder = options.placeholder;
|
||||
}
|
||||
if (options.disabled !== undefined) {
|
||||
input.disabled = options.disabled;
|
||||
}
|
||||
if (options.typeahead !== undefined) {
|
||||
var typeaheadOption = options.typeahead;
|
||||
$('#'+input.id).typeahead(typeaheadOption);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
__create_input(options) {
|
||||
var input = document.createElement('input');
|
||||
input.classList.add("form-group");
|
||||
input.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
if (options.style !== undefined) {
|
||||
input.style = options.style;
|
||||
}
|
||||
if (options.placeholder !== undefined) {
|
||||
input.placeholder = options.placeholder;
|
||||
}
|
||||
if (options.disabled !== undefined) {
|
||||
input.disabled = options.disabled;
|
||||
}
|
||||
if (options.typeahead !== undefined) {
|
||||
var typeaheadOption = options.typeahead;
|
||||
$('#'+input.id).typeahead(typeaheadOption);
|
||||
}
|
||||
return input;
|
||||
}
|
||||
|
||||
__create_select(select_options) {
|
||||
var select = document.createElement('select');
|
||||
select.classList.add("form-group");
|
||||
select.id = select_options.id !== undefined ? select_options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
select.style.width = "100%";
|
||||
this.__add_options_to_select(select, select_options.options);
|
||||
if(select_options.default !== undefined) {
|
||||
select.value = select_options.default;
|
||||
}
|
||||
return select;
|
||||
}
|
||||
__create_select(select_options) {
|
||||
var select = document.createElement('select');
|
||||
select.classList.add("form-group");
|
||||
select.id = select_options.id !== undefined ? select_options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
|
||||
select.style.width = "100%";
|
||||
this.__add_options_to_select(select, select_options.options);
|
||||
if(select_options.default !== undefined) {
|
||||
select.value = select_options.default;
|
||||
}
|
||||
return select;
|
||||
}
|
||||
|
||||
__add_options_to_select(select, options) {
|
||||
for(var value of options) {
|
||||
var option = document.createElement('option');
|
||||
if (Array.isArray(value)) { // array of type [value, text]
|
||||
option.value = value[1];
|
||||
option.innerHTML = value[1];
|
||||
} else { // only value, text=value
|
||||
option.value = value;
|
||||
option.innerHTML = value;
|
||||
}
|
||||
select.appendChild(option);
|
||||
}
|
||||
}
|
||||
__add_options_to_select(select, options) {
|
||||
for(var value of options) {
|
||||
var option = document.createElement('option');
|
||||
if (Array.isArray(value)) { // array of type [value, text]
|
||||
option.value = value[1];
|
||||
option.textContent = value[1];
|
||||
} else { // only value, text=value
|
||||
option.value = value;
|
||||
option.textContent = value;
|
||||
}
|
||||
select.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
__uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
__uuidv4() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -909,7 +909,7 @@ function multiSelectExportEvents() {
|
|||
var selected = [];
|
||||
$(".select").each(function() {
|
||||
if ($(this).is(":checked")) {
|
||||
var temp = $(this).data("id");
|
||||
var temp = $(this).data("uuid");
|
||||
if (temp != null) {
|
||||
selected.push(temp);
|
||||
}
|
||||
|
@ -1220,13 +1220,12 @@ function openGenericModal(url, modalData, callback) {
|
|||
} else {
|
||||
htmlData = data;
|
||||
}
|
||||
$('body').append(htmlData);
|
||||
$(document.body).append(htmlData);
|
||||
$('#genericModal').modal().on('shown', function() {
|
||||
if (callback !== undefined) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
error: function (data, textStatus, errorThrown) {
|
||||
showMessage('fail', textStatus + ": " + errorThrown);
|
||||
|
@ -3969,7 +3968,7 @@ function flashErrorPopover() {
|
|||
$("#gray_out").fadeIn();
|
||||
}
|
||||
|
||||
$('body').on('click', function (e) {
|
||||
$(document.body).on('click', function (e) {
|
||||
$('[data-toggle=popover]').each(function () {
|
||||
// hide any open popovers when the anywhere else in the body is clicked
|
||||
if (typeof currentPopover !== 'undefined' && currentPopover !== '') {
|
||||
|
@ -4766,7 +4765,7 @@ $(document.body).on('click', '.quickSelect', function() {
|
|||
selection.addRange(range);
|
||||
});
|
||||
|
||||
// Any link with data-paginator attribute will be treat as AJAX paginator
|
||||
// Any link with data-paginator attribute will be treated as AJAX paginator
|
||||
$(document.body).on('click', 'a[data-paginator]', function (e) {
|
||||
e.preventDefault();
|
||||
var paginatorTarget = $(this).attr('data-paginator');
|
||||
|
@ -4782,6 +4781,12 @@ $(document.body).on('click', 'a[data-paginator]', function (e) {
|
|||
});
|
||||
});
|
||||
|
||||
// Any link with modal-open class will be treated as generic modal
|
||||
$(document.body).on('click', 'a.modal-open', function (e) {
|
||||
e.preventDefault();
|
||||
openGenericModal($(this).attr('href'));
|
||||
});
|
||||
|
||||
function queryEventLock(event_id, timestamp) {
|
||||
if (!document.hidden) {
|
||||
$.ajax({
|
||||
|
@ -5303,7 +5308,7 @@ function redirectIdSelection(scope, action) {
|
|||
}
|
||||
}
|
||||
|
||||
$('body').on('click', '.hex-value-convert', function() {
|
||||
$(document.body).on('click', '.hex-value-convert', function() {
|
||||
var $hexValueSpan = $(this).parent().children(':first-child');
|
||||
var val = $hexValueSpan.text().trim();
|
||||
if (!$hexValueSpan.hasClass('binary-representation')) {
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue