Merge branch 'develop' into 2.4

pull/8286/head
iglocska 2022-04-19 15:26:25 +02:00
commit 1c0df3687a
No known key found for this signature in database
GPG Key ID: BEA224F1FEF113AC
124 changed files with 4844 additions and 22513 deletions

View File

@ -30,10 +30,6 @@ jobs:
with:
submodules: 'recursive'
# Stop mysql
- name: Shutdown Ubuntu MySQL (SUDO)
run: sudo service mysql stop
# Run mariadb
- uses: getong/mariadb-action@v1.1
with:
@ -61,21 +57,22 @@ jobs:
echo "USER=`id -u -n`" >> $GITHUB_ENV
echo "HOST=localhost" >> $GITHUB_ENV
# Runs a set of commands using the runners shell
- name: Install deps
- name: Install system deps
env:
php_version: ${{ matrix.php }}
run: |
sudo apt-get -y update
# Repo is missing for unknown reason
LC_ALL=C.UTF-8 sudo apt-add-repository ppa:ondrej/php -y
if [[ $php_version == "7.2" ]]; then
# hotfix due to: https://bugs.php.net/bug.php?id=81640 TODO: remove after libpcre2-8-0:10.36 gets to stable channel
sudo apt --fix-broken install
fi
sudo apt-get -y install curl python3 python3-zmq python3-requests python3-pip python3-nose python3-redis python3-lxml apache2 libapache2-mod-php$php_version
sudo pip3 install virtualenv # virtualenv must be instaled from pip and not from ubuntu packages
curl -sSL https://install.python-poetry.org | python -
sudo apt-get -y update
# Repo is missing for unknown reason
LC_ALL=C.UTF-8 sudo apt-add-repository ppa:ondrej/php -y
if [[ $php_version == "7.2" ]]; then
# hotfix due to: https://bugs.php.net/bug.php?id=81640 TODO: remove after libpcre2-8-0:10.36 gets to stable channel
sudo apt-get --fix-broken install
fi
sudo apt-get -y install curl python3 python3-pip python3-virtualenv apache2 libapache2-mod-php$php_version
# Runs a set of commands using the runners shell
- name: Install deps
run: |
sudo chown $USER:www-data $HOME/.composer
pushd app
sudo -H -u $USER php composer.phar install --no-progress
@ -149,32 +146,33 @@ jobs:
- name: Configure MISP
run: |
sudo -E su $USER -c 'app/Console/cake userInit -q | sudo tee ./key.txt'
sudo -u $USER app/Console/cake userInit -q | sudo tee ./key.txt
echo "AUTH=`cat key.txt`" >> $GITHUB_ENV
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Session.autoRegenerate" 0'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Session.timeout" 600'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Session.cookieTimeout" 3600'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.host_org_id" 1'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.email" "info@admin.test"'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.disable_emailing" false'
sudo -E su $USER -c 'app/Console/cake Admin setSetting --force "debug" true'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.CustomAuth_disable_logout" false'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.redis_host" "127.0.0.1"'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.redis_port" 6379'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.redis_database" 13'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.redis_password" ""'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "GnuPG.email" "info@admin.test"'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "GnuPG.homedir" "`pwd`/.gnupg"'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "GnuPG.password" "travistest"'
sudo -u $USER app/Console/cake Admin setSetting "Session.autoRegenerate" 0
sudo -u $USER app/Console/cake Admin setSetting "Session.timeout" 600
sudo -u $USER app/Console/cake Admin setSetting "Session.cookieTimeout" 3600
sudo -u $USER app/Console/cake Admin setSetting "MISP.host_org_id" 1
sudo -u $USER app/Console/cake Admin setSetting "MISP.email" "info@admin.test"
sudo -u $USER app/Console/cake Admin setSetting "MISP.disable_emailing" false
sudo -u $USER app/Console/cake Admin setSetting --force "debug" true
sudo -u $USER app/Console/cake Admin setSetting "Plugin.CustomAuth_disable_logout" false
sudo -u $USER app/Console/cake Admin setSetting "MISP.redis_host" "127.0.0.1"
sudo -u $USER app/Console/cake Admin setSetting "MISP.redis_port" 6379
sudo -u $USER app/Console/cake Admin setSetting "MISP.redis_database" 13
sudo -u $USER app/Console/cake Admin setSetting "MISP.redis_password" ""
sudo -u $USER app/Console/cake Admin setSetting "GnuPG.email" "info@admin.test"
sudo -u $USER app/Console/cake Admin setSetting "GnuPG.homedir" "`pwd`/.gnupg"
sudo -u $USER app/Console/cake Admin setSetting "GnuPG.password" "travistest"
sudo -u $USER app/Console/cake Admin setSetting "MISP.download_gpg_from_homedir" 1
- name: Configure ZMQ
run: |
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_host" "127.0.0.1"'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_port" 6379'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_database" 1'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_password" ""'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_enable" 1'
sudo -E su $USER -c 'app/Console/cake Admin setSetting "Plugin.ZeroMQ_audit_notifications_enable" 1'
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_host" "127.0.0.1"
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_port" 6379
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_database" 1
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_redis_password" ""
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_enable" 1
sudo -u $USER app/Console/cake Admin setSetting "Plugin.ZeroMQ_audit_notifications_enable" 1
- name: Update Galaxies
run: sudo -E su $USER -c 'app/Console/cake Admin updateGalaxies'
@ -209,16 +207,7 @@ jobs:
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.python_bin" "$GITHUB_WORKSPACE/venv/bin/python"'
. ./venv/bin/activate
export PYTHONPATH=$PYTHONPATH:./app/files/scripts
pushd ./app/files/scripts/cti-python-stix2
pip install .
popd
pushd ./app/files/scripts/python-stix
pip install .
popd
pushd PyMISP
pip install .[fileobjects,email]
popd
pip install zmq redis plyara
pip install ./PyMISP[fileobjects,email] ./app/files/scripts/python-stix ./app/files/scripts/cti-python-stix2 pyzmq redis plyara
deactivate
- name: Test if apache is working
@ -242,31 +231,32 @@ jobs:
- name: Run PHP tests
run: |
./app/Vendor/bin/parallel-lint --exclude app/Lib/cakephp/ --exclude app/Vendor/ --exclude app/Lib/random_compat/ -e php,ctp app/
./app/Vendor/bin/phpunit app/Test/
sudo -u www-data ./app/Vendor/bin/phpunit app/Test/
- name: Run tests
run: |
export PATH=$HOME/.local/env:$PATH # enable poetry binary
pushd tests
./curl_tests_GH.sh $AUTH $HOST
popd
sudo chmod -R g+ws `pwd`/app/tmp/logs
. ./venv/bin/activate
pushd PyMISP
poetry install -E fileobjects -E openioc -E virustotal -E docs -E pdfexport -E email
poetry run python tests/testlive_comprehensive.py
poetry add lxml
poetry run python ../tests/testlive_security.py -v
poetry run python ../tests/testlive_sync.py
poetry run python ../tests/testlive_comprehensive_local.py -v
poetry run python tests/test_mispevent.py
python tests/testlive_comprehensive.py
popd
python tests/testlive_security.py -v
python tests/testlive_sync.py
python tests/testlive_comprehensive_local.py -v
pushd PyMISP
python tests/test_mispevent.py
popd
cp PyMISP/tests/keys.py PyMISP/examples/events/
pushd PyMISP/examples/events/
poetry run python ./create_massive_dummy_events.py -l 5 -a 30
python ./create_massive_dummy_events.py -l 5 -a 30
popd
python3 tools/misp-feed/validate.py
python tools/misp-feed/validate.py
deactivate
- name: Logs
if: ${{ always() }}

5
.gitignore vendored
View File

@ -107,3 +107,8 @@ vagrant/.vagrant/
vagrant/*.log
/app/Lib/Dashboard/Custom/*
!/app/Lib/Dashboard/Custom/empty
/app/View/Emails/html/Custom/*
!/app/View/Emails/html/Custom/empty
/app/View/Emails/text/Custom/*
!/app/View/Emails/text/Custom/empty

View File

@ -187,8 +187,9 @@ class EventShell extends AppShell
$this->Job->id = $id;
$export_type = $this->args[2];
file_put_contents('/tmp/test', $export_type);
$typeData = $this->Event->export_types[$export_type];
if (!in_array($export_type, array_keys($this->Event->export_types))) {
$exportTypes = $this->Event->exportTypes();
$typeData = $exportTypes[$export_type];
if (!in_array($export_type, array_keys($exportTypes))) {
$this->Job->saveField('progress', 100);
$timeDelta = (time()-$timeStart);
$this->Job->saveField('message', 'Job Failed due to invalid export format. (in '.$timeDelta.'s)');
@ -385,7 +386,7 @@ class EventShell extends AppShell
// the special cache files containing all events
$i = 0;
foreach ($users as $user) {
foreach ($this->Event->export_types as $k => $type) {
foreach ($this->Event->exportTypes() as $k => $type) {
if ($k == 'stix') continue;
$this->Job->cache($k, $user['User']);
$i++;

View File

@ -0,0 +1,361 @@
<?php
class Ls22Shell extends AppShell
{
public $uses = ['Server'];
private $__servers = [];
private function __getInstances($path)
{
if (empty($path)) {
$path = 'instances.csv';
}
$file = file_get_contents($path);
$lines = explode(PHP_EOL, $file);
foreach ($lines as $k => $line) {
if ($k === 0) {
continue;
}
$fields = explode(',', $line);
if (count($fields) === 4 && $fields[1] === 'admin@admin.test') {
$this->__servers[] = [
'Server' => [
'url' => trim($fields[0]),
'authkey' => trim($fields[2])
]
];
}
}
}
public function getOptionParser()
{
$parser = parent::getOptionParser();
$parser->addSubcommand('enableTaxonomy', [
'help' => __('Enable a taxonomy with all its tags.'),
'parser' => array(
'options' => array(
'instances' => [
'help' => 'Path to the instance file, by default "instances.csv" from the local directory',
'short' => 'i',
'required' => true
],
'taxonomy' => [
'help' => 'The name of the taxonomy to enable, such as "tlp"',
'short' => 't',
'required' => true
],
'misp_url_filter' => [
'help' => 'The url of the instance to enable it for - otherwise all are selected',
'short' => 'm',
'required' => false
]
),
),
]);
$parser->addSubcommand('addWarninglist', [
'help' => __('Inject warninglist'),
'parser' => array(
'options' => array(
'instances' => [
'help' => 'Path to the instance file, by default "instances.csv" from the local directory',
'short' => 'i',
'required' => true
],
'warninglist' => [
'help' => 'Path to the warninglist file',
'short' => 'w',
'required' => true
]
),
),
]);
$parser->addSubcommand('status', [
'help' => __('Check if the instances are available / the API key works.'),
'parser' => array(
'options' => array(
'instances' => [
'help' => 'Path to the instance file, by default "instances.csv" from the local directory',
'short' => 'i',
'required' => true
]
),
),
]);
$parser->addSubcommand('scores', [
'help' => __('Generate the scores for all BTs.'),
'parser' => array(
'options' => array(
'instances' => [
'help' => 'Path to the instance file, by default "instances.csv" from the local directory',
'short' => 'i',
'required' => true
],
'server_url' => [
'help' => 'URL of the server to query for the scores. If nothing is specified, the first valid entry from instances.csv is taken.',
'short' => 's',
'required' => false
],
'from' => [
'help' => 'Lower bound of the date. Accepts timestamp or date distance (such as 1d or 5h). Defaults to unbounded.',
'short' => 'f',
'required' => false
],
'to' => [
'help' => 'Upper bound of the date. Accepts timestamp or date distance (such as 1d or 5h). Defaults to unbounded.',
'short' => 't',
'required' => false
]
),
),
]);
return $parser;
}
public function enableTaxonomy()
{
$taxonomyToEnable = $this->param('taxonomy');
$instanceFilter = $this->param('misp_url_filter');
if (empty($taxonomyToEnable)) {
$this->error('No taxonomy provided', 'Provide a taxonomy by specifying the -t or --taxonomy options.');
}
$this->__getInstances($this->param('instances'));
$results = [];
foreach ($this->__servers as $server) {
if (!empty($instanceFilter) && strtolower(trim($server['Server']['url'])) !== strtolower(trim($instanceFilter))) {
continue;
}
$HttpSocket = $this->Server->setupHttpSocket($server, null);
$request = $this->Server->setupSyncRequest($server, 'Server');
$response = $HttpSocket->get($server['Server']['url'] . '/taxonomies/index', false, $request);
if (!$response->isOk()) {
$this->out($server['Server']['url'] . ': ' . '<error>Connection or auth failed</error>', 1, Shell::NORMAL);
}
$taxonomies = json_decode($response->body, true);
$success = false;
foreach ($taxonomies as $taxonomy) {
if ($taxonomy['Taxonomy']['namespace'] === $taxonomyToEnable) {
$response = $HttpSocket->post($server['Server']['url'] . '/taxonomies/enable/' . $taxonomy['Taxonomy']['id'], '{}', $request);
if ($response->isOk()) {
$response = $HttpSocket->post($server['Server']['url'] . '/taxonomies/addTag/' . $taxonomy['Taxonomy']['id'], '{}', $request);
if ($response->isOk()) {
$success = true;
}
}
}
}
$results[$server['Server']['url']] = $success ? 'Success' : 'Failed';
$statusWrapped = sprintf(
'<%s>%s</%s>',
$success ? 'info' : 'error',
$results[$server['Server']['url']],
$success ? 'info' : 'error'
);
$this->out($server['Server']['url'] . ': ' . $statusWrapped, 1, Shell::NORMAL);
}
}
public function status()
{
$this->__getInstances($this->param('instances'));
$results = [];
foreach ($this->__servers as $server) {
$HttpSocket = $this->Server->setupHttpSocket($server, null);
$request = $this->Server->setupSyncRequest($server, 'Server');
$start_time = microtime(true);
$response = $HttpSocket->get($server['Server']['url'] . '/users/view/me', false, $request);
$execution_time = round((microtime(true) - $start_time) * 1000);
$statusWrapped = sprintf(
'<%s>%s</%s>',
$response->isOk() ? 'info' : 'error',
$response->isOk() ? 'OK (' . $execution_time . 'ms)' : 'Failed. (' . $response->code . ')',
$response->isOk() ? 'info' : 'error'
);
$this->out($server['Server']['url'] . ': ' . $statusWrapped, 1, Shell::NORMAL);
$results[$server['Server']['url']] = $response->isOk() ? $execution_time : false;
}
}
public function addWarninglist()
{
$path = $this->param('warninglist');
if (empty($path)) {
$this->error('No warninglist provided', 'Provide a path to a file containing a warninglist JSON by specifying the -w or --warninglist options.');
}
$file = file_get_contents($path);
$this->__getInstances($this->param('instances'));
$results = [];
foreach ($this->__servers as $server) {
$HttpSocket = $this->Server->setupHttpSocket($server, null);
$request = $this->Server->setupSyncRequest($server, 'Server');
$start_time = microtime(true);
$response = $HttpSocket->post($server['Server']['url'] . '/warninglists/add', $file, $request);
$statusWrapped = sprintf(
'<%s>%s</%s>',
$response->isOk() ? 'info' : 'error',
$response->isOk() ? 'OK' : 'Could not create warninglist',
$response->isOk() ? 'info' : 'error'
);
$this->out($server['Server']['url'] . ': ' . $statusWrapped, 1, Shell::NORMAL);
}
}
public function scores()
{
$results = [];
$this->__getInstances($this->param('instances'));
$server = null;
if (!empty($this->param['server_url'])) {
foreach ($this->__servers as $temp_server) {
if ($temp_server['Server']['url'] === $this->param['server_url']) {
$server = $temp_server;
}
}
} else {
$server = $this->__servers[0];
}
$HttpSocket = $this->Server->setupHttpSocket($server, null);
$request = $this->Server->setupSyncRequest($server);
$response = $HttpSocket->get($server['Server']['url'] . '/organisations/index', false, $request);
$orgs = json_decode($response->body(), true);
$this->out(__('Organisations fetched. %d found.', count($orgs)), 1, Shell::VERBOSE);
$org_mapping = [];
foreach ($orgs as $org) {
$name = explode(' ', $org['Organisation']['name']);
if ($name[0] !== 'BT') {
continue;
}
$org_mapping[$org['Organisation']['name']] = $org['Organisation']['id'];
}
foreach ($org_mapping as $org_name => $org_id) {
$time_range = [];
if (!empty($this->param['from'])) {
$time_range[] = $this->param['from'];
}
if (!empty($this->param['to'])) {
if (empty($time_range)) {
$time_range[] = '365d';
}
$time_range[] = $this->param['to'];
}
$params = [
'org' => $org_id
];
if (!empty($time_range)) {
$params['publish_timestamp'] = $time_range;
}
$response = $HttpSocket->post($server['Server']['url'] . '/events/restSearch', json_encode($params), $request);
$events = json_decode($response->body(), true);
$this->out(__('Events fetched from %s. %d found.', $org_name, count($events['response'])), 1, Shell::VERBOSE);
$results[$org_name] = [
'attribute_count' => 0,
'object_count' => 0,
'connected_elements' => 0,
'event_tags' => 0,
'attribute_tags' => 0,
'attack' => 0,
'other' => 0,
'attribute_attack' => 0,
'attribute_other' => 0,
'score' => 0
];
foreach ($events['response'] as $event) {
if (!empty($event['Event']['Tag'])) {
foreach ($event['Event']['Tag'] as $tag) {
if (substr($tag['name'], 0, 32) === 'misp-galaxy:mitre-attack-pattern') {
$results[$org_name]['attack'] += 1;
} else {
$results[$org_name]['other'] += 1;
}
}
}
if (!empty($event['Event']['Galaxy'])) {
foreach ($event['Event']['Galaxy'] as $galaxy) {
if ($galaxy['type'] === 'mitre-attack-pattern') {
$results[$org_name]['attack'] += 1;
} else {
$results[$org_name]['other'] += 1;
}
}
}
foreach ($event['Event']['Attribute'] as $attribute) {
if (!empty($attribute['referenced_by'])) {
$results[$org_name]['connected_elements'] +=1;
}
if (!empty($attribute['Tag'])) {
foreach ($attribute['Tag'] as $tag) {
if (substr($tag['name'], 0, 32) === 'misp-galaxy:mitre-attack-pattern') {
$results[$org_name]['attribute_attack'] += 1;
} else {
$results[$org_name]['attribute_other'] += 1;
}
}
}
}
$results[$org_name]['attribute_count'] += count($event['Event']['Attribute']);
if (!empty($event['Event']['Object'])) {
foreach ($event['Event']['Object'] as $object) {
$results[$org_name]['attribute_count'] += count($object['Attribute']);
$results[$org_name]['object_count'] += 1;
if (!empty($object['ObjectReference'])) {
$results[$org_name]['connected_elements'] += 1;
}
foreach ($object['Attribute'] as $attribute) {
if (!empty($attribute['Tag'])) {
foreach ($attribute['Tag'] as $tag) {
if (substr($tag['name'], 0, 32) === 'misp-galaxy:mitre-attack-pattern') {
$results[$org_name]['attribute_attack'] += 1;
} else {
$results[$org_name]['attribute_other'] += 1;
}
}
}
}
}
}
}
}
$scores = [];
foreach ($results as $k => $result) {
$totalCount = $result['attribute_count'] + $result['object_count'];
if ($totalCount) {
$results[$k]['metrics']['connectedness'] = 100 * ($result['connected_elements'] / ($result['attribute_count'] + $result['object_count']));
$results[$k]['metrics']['attack_weight'] = 100 * (2*($result['attack']) + $result['attribute_attack']) / ($result['attribute_count'] + $result['object_count']);
$results[$k]['metrics']['other_weight'] = 100 * (2*($result['other']) + $result['attribute_other']) / ($result['attribute_count'] + $result['object_count']);
}
foreach (['connectedness', 'attack_weight', 'other_weight'] as $metric) {
if (empty($results[$k]['metrics'][$metric])) {
$results[$k]['metrics'][$metric] = 0;
}
if ($results[$k]['metrics'][$metric] > 100) {
$results[$k]['metrics'][$metric] = 100;
}
}
$results[$k]['score'] = round(40 * $results[$k]['metrics']['connectedness'] + 40 * $results[$k]['metrics']['attack_weight'] + 20 * $results[$k]['metrics']['other_weight']) / 100;
$scores[$k] = $results[$k]['score'];
}
arsort($scores, SORT_DESC);
$this->out(str_repeat('=', 128), 1, Shell::NORMAL);
$this->out(sprintf(
'| %s | %s | %s |',
str_pad('Org', 10, ' ', STR_PAD_RIGHT),
str_pad('Graph', 100, ' ', STR_PAD_RIGHT),
str_pad('Score', 8, ' ', STR_PAD_RIGHT)
), 1, Shell::NORMAL);
$this->out(str_repeat('=', 128), 1, Shell::NORMAL);
foreach ($scores as $org => $score) {
$score_string = str_repeat('█', round($score));
$this->out(sprintf(
'| %s | %s | %s |',
str_pad($org, 10, ' ', STR_PAD_RIGHT),
sprintf(
'<info>%s</info>%s',
$score_string,
str_repeat(' ', 100 - mb_strlen($score_string))
),
str_pad($score . '%', 8, ' ', STR_PAD_RIGHT)
), 1, Shell::NORMAL);
}
$this->out(str_repeat('=', 128), 1, Shell::NORMAL);
}
}

View File

@ -1,5 +1,3 @@
http://download.geonames.org/export/dump/countryInfo.txt
<?php
class SupportShell extends AppShell {

View File

@ -0,0 +1,302 @@
<?php
App::uses('AppController', 'Controller');
class ApiController extends AppController
{
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions[] = 'getApiInfo';
}
public function openapi()
{
$this->set('title_for_layout', __('OpenAPI'));
}
public function viewDeprecatedFunctionUse()
{
$server = ClassRegistry::init('Server');
$data = $this->Deprecation->getDeprecatedAccessList($server);
if ($this->_isRest()) {
return $this->RestResponse->viewData($data, $this->response->type());
} else {
$this->layout = false;
$this->set('data', $data);
}
}
public function getAllApis()
{
$allValidApis = $this->RestResponse->getAllApis($this->Auth->user());
$allValidApisFieldsConstraint = $this->RestResponse->getAllApisFieldsConstraint($this->Auth->user());
$output = [
'allValidApis' => $allValidApis,
'fieldsConstraint' => $allValidApisFieldsConstraint,
];
return $this->RestResponse->viewData($output, 'json');
}
public function getApiInfo()
{
$relative_path = $this->request->data['url'];
$result = $this->RestResponse->getApiInfo($relative_path);
if ($this->_isRest()) {
if (!empty($result)) {
$result['api_info'] = $result;
}
return $this->RestResponse->viewData($result, $this->response->type());
} else {
if (empty($result)) {
return $this->RestResponse->viewData('&nbsp;', $this->response->type());
}
$this->layout = false;
$this->autoRender = false;
$this->set('api_info', $result);
$this->render('ajax/get_api_info');
}
}
public function rest()
{
if ($this->request->is('post')) {
$request = $this->request->data;
if (!empty($request['Server'])) {
$request = $this->request->data['Server'];
}
$curl = '';
$python = '';
try {
$result = $this->__doRestQuery($request, $curl, $python);
$this->set('curl', $curl);
$this->set('python', $python);
if (!$result) {
$this->Flash->error('Something went wrong. Make sure you set the http method, body (when sending POST requests) and URL correctly.');
} else {
$this->set('data', $result);
}
} catch (Exception $e) {
$this->Flash->error(__('Something went wrong. %s', $e->getMessage()));
}
}
$header = sprintf(
"Authorization: %s \nAccept: application/json\nContent-type: application/json",
__('YOUR_API_KEY')
);
$this->set('header', $header);
$allAccessibleApis = $this->RestResponse->getAccessibleApis($this->Auth->user());
$this->set('allAccessibleApis', $allAccessibleApis);
$this->set('title_for_layout', __('REST client'));
}
/**
* @param array $request
* @param string $curl
* @param string $python
* @return array|false
*/
private function __doRestQuery(array $request, &$curl = false, &$python = false)
{
$params = array();
$logHeaders = $request['header'];
if (!empty(Configure::read('Security.advanced_authkeys'))) {
$logHeaders = explode("\n", $request['header']);
foreach ($logHeaders as $k => $header) {
if (strpos($header, 'Authorization') !== false) {
$logHeaders[$k] = 'Authorization: ' . __('YOUR_API_KEY');
}
}
$logHeaders = implode("\n", $logHeaders);
}
if (empty($request['body'])) {
$historyBody = '';
} else if (strlen($request['body']) > 65535) {
$historyBody = ''; // body is too long to save into history table
} else {
$historyBody = $request['body'];
}
$rest_history_item = array(
'headers' => $logHeaders,
'body' => $historyBody,
'url' => $request['url'],
'http_method' => $request['method'],
'use_full_path' => empty($request['use_full_path']) ? false : $request['use_full_path'],
'show_result' => $request['show_result'],
'skip_ssl' => $request['skip_ssl_validation'],
'bookmark' => $request['bookmark'],
'bookmark_name' => $request['name'],
'timestamp' => time(),
);
if (!empty($request['url'])) {
if (empty($request['use_full_path']) || empty(Configure::read('Security.rest_client_enable_arbitrary_urls'))) {
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
$url = empty(Configure::read('Security.rest_client_baseurl')) ? (Configure::read('MISP.baseurl') . $path) : (Configure::read('Security.rest_client_baseurl') . $path);
unset($request['url']);
} else {
$url = $request['url'];
}
} else {
throw new InvalidArgumentException('URL not set.');
}
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
$params['ssl_verify_host'] = false;
$params['ssl_verify_peer_name'] = false;
$params['ssl_allow_self_signed'] = true;
}
$params['timeout'] = 300;
App::uses('HttpSocketExtended', 'Tools');
$HttpSocket = new HttpSocketExtended($params);
$temp_headers = empty($request['header']) ? [] : explode("\n", $request['header']);
$request['header'] = array(
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'MISP REST Client',
);
foreach ($temp_headers as $header) {
$header = explode(':', $header);
$header[0] = trim($header[0]);
$header[1] = trim($header[1]);
$request['header'][$header[0]] = $header[1];
}
$start = microtime(true);
if (
!empty($request['method']) &&
$request['method'] === 'GET'
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('get', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->get($url, false, array('header' => $request['header']));
} elseif (
!empty($request['method']) &&
$request['method'] === 'POST' &&
!empty($request['body'])
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('post', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->post($url, $request['body'], array('header' => $request['header']));
} elseif (
!empty($request['method']) &&
$request['method'] === 'DELETE'
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('delete', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->delete($url, false, array('header' => $request['header']));
} else {
return false;
}
$viewData = [
'duration' => round((microtime(true) - $start) * 1000, 2) . ' ms',
'url' => $url,
'code' => $response->code,
'headers' => $response->headers,
];
if (!empty($request['show_result'])) {
$viewData['data'] = $response->body;
} else {
if ($response->isOk()) {
$viewData['data'] = 'Success.';
} else {
$viewData['data'] = 'Something went wrong.';
}
}
$rest_history_item['outcome'] = $response->code;
$this->loadModel('RestClientHistory');
$this->RestClientHistory->insert($this->Auth->user(), $rest_history_item);
return $viewData;
}
private function __generatePythonScript(array $request, $url)
{
$slashCounter = 0;
$baseurl = '';
$relative = '';
$verifyCert = ($url[4] === 's') ? 'True' : 'False';
for ($i = 0; $i < strlen($url); $i++) {
//foreach ($url as $url[$i]) {
if ($url[$i] === '/') {
$slashCounter += 1;
if ($slashCounter == 3) {
continue;
}
}
if ($slashCounter < 3) {
$baseurl .= $url[$i];
} else {
$relative .= $url[$i];
}
}
$python_script =
sprintf(
'misp_url = \'%s\'
misp_key = \'%s\'
misp_verifycert = %s
relative_path = \'%s\'
body = %s
from pymisp import ExpandedPyMISP
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
misp.direct_call(relative_path, body)
',
$baseurl,
$request['header']['Authorization'],
$verifyCert,
$relative,
(empty($request['body']) ? 'None' : $request['body'])
);
return $python_script;
}
private function __generateCurlQuery($type, array $request, $url)
{
if ($type === 'get') {
$curl = sprintf(
'curl \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s %s',
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
} else {
$curl = sprintf(
'curl \%s -d \'%s\' \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s -X POST %s',
PHP_EOL,
json_encode(json_decode($request['body'])),
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
}
return $curl;
}
}

View File

@ -34,7 +34,7 @@ class AppController extends Controller
public $helpers = array('OrgImg', 'FontAwesome', 'UserName');
private $__queryVersion = '138';
private $__queryVersion = '139';
public $pyMispVersion = '2.4.157';
public $phpmin = '7.2';
public $phprec = '7.4';
@ -202,20 +202,7 @@ class AppController extends Controller
if (empty($dataToDecode)) {
return null;
}
try {
if (defined('JSON_THROW_ON_ERROR')) {
// JSON_THROW_ON_ERROR is supported since PHP 7.3
return json_decode($dataToDecode, true, 512, JSON_THROW_ON_ERROR);
} else {
$decoded = json_decode($dataToDecode, true);
if ($decoded === null) {
throw new UnexpectedValueException('Could not parse JSON: ' . json_last_error_msg(), json_last_error());
}
return $decoded;
}
} catch (Exception $e) {
throw new HttpException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.', 405, $e);
}
return $this->_jsonDecode($dataToDecode);
};
// Throw exception if JSON in request is invalid. Default CakePHP behaviour would just ignore that error.
$this->RequestHandler->addInputType('json', [$jsonDecode]);
@ -376,7 +363,7 @@ class AppController extends Controller
{
// Notifications and homepage is not necessary for AJAX or REST requests
$user = $this->Auth->user();
if ($user && !$this->_isRest() && !$this->request->is('ajax')) {
if ($user && !$this->_isRest() && isset($this->User) && !$this->request->is('ajax')) {
$hasNotifications = $this->User->hasNotifications($user);
$this->set('hasNotifications', $hasNotifications);
@ -1450,4 +1437,27 @@ class AppController extends Controller
}
return parent::_getViewObject();
}
/**
* Decode JSON with proper error handling.
* @param string $dataToDecode
* @return mixed
*/
protected function _jsonDecode($dataToDecode)
{
try {
if (defined('JSON_THROW_ON_ERROR')) {
// JSON_THROW_ON_ERROR is supported since PHP 7.3
return json_decode($dataToDecode, true, 512, JSON_THROW_ON_ERROR);
} else {
$decoded = json_decode($dataToDecode, true);
if ($decoded === null) {
throw new UnexpectedValueException('Could not parse JSON: ' . json_last_error_msg(), json_last_error());
}
return $decoded;
}
} catch (Exception $e) {
throw new HttpException('Invalid JSON input. Make sure that the JSON input is a correctly formatted JSON string. This request has been blocked to avoid an unfiltered request.', 405, $e);
}
}
}

View File

@ -940,22 +940,14 @@ class AttributesController extends AppController
if (!$changed) {
return new CakeResponse(array('body'=> json_encode(array('errors'=> array('value' => 'nochange'))), 'status'=>200, 'type' => 'json'));
}
$date = new DateTime();
$attribute['Attribute']['timestamp'] = $date->getTimestamp();
$time = time();
$attribute['Attribute']['timestamp'] = $time;
$fieldsToSave = ['timestamp'];
if ($changedKey === 'value') {
$fieldsToSave[] = 'value1';
$fieldsToSave[] = 'value2';
} else {
$fieldsToSave[] = $changedKey;
}
if ($this->Attribute->save($attribute, true, $fieldsToSave)) {
$this->Attribute->Event->unpublishEvent($attribute['Attribute']['event_id'], false, $date->getTimestamp());
if ($this->Attribute->save($attribute)) {
$this->Attribute->Event->unpublishEvent($attribute['Attribute']['event_id'], false, $time);
if ($attribute['Attribute']['object_id'] != 0) {
$this->Attribute->Object->updateTimestamp($attribute['Attribute']['object_id'], $date->getTimestamp());
$this->Attribute->Object->updateTimestamp($attribute['Attribute']['object_id'], $time);
}
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => 'Field updated.', 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
@ -1982,12 +1974,6 @@ class AttributesController extends AppController
$result = $this->Attribute->shortDist[$result];
} elseif ($field === 'to_ids') {
$result = ($result == 0 ? 'No' : 'Yes');
} elseif ($field === 'timestamp') {
if (isset($result)) {
$result = date('Y-m-d', $result);
} else {
echo '&nbsp';
}
} elseif ($field === 'value') {
$this->loadModel('Warninglist');
$attribute['Attribute'] = $this->Warninglist->checkForWarning($attribute['Attribute']);

View File

@ -141,10 +141,10 @@ class AuthKeysController extends AppController
}
$params = [
'displayOnSuccess' => 'authkey_display',
'saveModelVariable' => ['authkey_raw'],
'override' => ['authkey' => null], // do not allow to use own key, always generate random one
'afterFind' => function ($authKey) { // remove hashed key from response
'afterFind' => function (array $authKey, array $savedData) { // remove hashed key from response
unset($authKey['AuthKey']['authkey']);
$authKey['AuthKey']['authkey_raw'] = $savedData['AuthKey']['authkey_raw'];
return $authKey;
}
];
@ -195,11 +195,10 @@ class AuthKeysController extends AppController
if ($this->IndexFilter->isRest()) {
return $this->restResponsePayload;
}
$this->loadModel('User');
$dropdownData = [
'user' => $this->User->find('list', [
'user' => $this->AuthKey->User->find('list', [
'sort' => ['username' => 'asc'],
'conditions' => $selectConditions
'conditions' => $selectConditions,
])
];
$this->set(compact('dropdownData'));

View File

@ -19,6 +19,13 @@ class ACLComponent extends Component
'queryACL' => array(),
'restSearch' => array('*'),
),
'api' => [
'rest' => ['perm_auth'],
'viewDeprecatedFunctionUse' => [],
'openapi' => ['*'],
'getApiInfo' => ['*'],
'getAllApis' => ['*'],
],
'attributes' => array(
'add' => array('perm_add'),
'add_attachment' => array('perm_add'),
@ -505,7 +512,6 @@ class ACLComponent extends Component
'eventBlockRule' => array(),
'fetchServersForSG' => array('perm_sharing_group'),
'filterEventIndex' => array(),
'getApiInfo' => array('*'),
'getAvailableSyncFilteringRules' => array('*'),
'getInstanceUUID' => array('perm_sync'),
'getPyMISPVersion' => array('*'),
@ -531,8 +537,6 @@ class ACLComponent extends Component
'releaseUpdateLock' => array(),
'resetRemoteAuthKey' => array(),
'removeOrphanedCorrelations' => array(),
'rest' => array('perm_auth'),
'openapi' => array('*'),
'restartDeadWorkers' => array(),
'restartWorkers' => array(),
'serverSettings' => array(),
@ -549,7 +553,6 @@ class ACLComponent extends Component
'updateProgress' => array(),
'updateSubmodule' => array(),
'uploadFile' => array(),
'viewDeprecatedFunctionUse' => array(),
'killAllWorkers' => [],
'cspReport' => ['*'],
'pruneDuplicateUUIDs' => array(),
@ -557,6 +560,7 @@ class ACLComponent extends Component
'upgrade2324' => array(),
'cleanModelCaches' => array(),
'updateDatabase' => array(),
'rest' => ['perm_auth'],
),
'shadowAttributes' => array(
'accept' => array('perm_add'),

View File

@ -90,7 +90,8 @@ class CRUDComponent extends Component
}
/** @var Model $model */
$model = $this->Controller->{$modelName};
if ($model->save($data)) {
$savedData = $model->save($data);
if ($savedData) {
if (isset($params['afterSave'])) {
$params['afterSave']($data);
}
@ -100,15 +101,11 @@ class CRUDComponent extends Component
'id' => $model->id
]
]);
if (!empty($params['saveModelVariable'])) {
foreach ($params['saveModelVariable'] as $var) {
if (isset($model->$var)) {
$data[$modelName][$var] = $model->$var;
}
}
if (empty($data)) {
throw new Exception("Something went wrong, saved data not found in database.");
}
if (isset($params['afterFind'])) {
$data = $params['afterFind']($data);
$data = $params['afterFind']($data, $savedData);
}
$message = __('%s added.', $modelName);
if ($this->Controller->IndexFilter->isRest()) {

View File

@ -48,7 +48,7 @@ class RestResponseComponent extends Component
'restSearch' => array(
'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.",
'mandatory' => array('returnFormat'),
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'attribute_timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'includeProposals', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'score', 'first_seen', 'last_seen'),
'optional' => array('page', 'limit', 'value' , 'type', 'category', 'org', 'tags', 'date', 'last', 'eventid', 'withAttachments', 'uuid', 'publish_timestamp', 'timestamp', 'attribute_timestamp', 'enforceWarninglist', 'to_ids', 'deleted', 'includeEventUuid', 'includeEventTags', 'event_timestamp', 'threat_level_id', 'eventinfo', 'sharinggroup', 'includeProposals', 'includeDecayScore', 'includeFullModel', 'decayingModel', 'excludeDecayed', 'score', 'first_seen', 'last_seen'),
'params' => array()
),
'addTag' => array(
@ -88,7 +88,7 @@ class RestResponseComponent extends Component
'restSearch' => array(
'description' => "Search MISP using a list of filter parameters and return the data in the selected format. The search is available on an event and an attribute level, just select the scope via the URL (/events/restSearch vs /attributes/restSearch). Besides the parameters listed, other, format specific ones can be passed along (for example: requested_attributes and includeContext for the CSV export). This API allows pagination via the page and limit parameters.",
'mandatory' => array('returnFormat'),
'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'date', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo', 'excludeLocalTags', 'threat_level_id'),
'optional' => array('page', 'limit', 'value', 'type', 'category', 'org', 'tag', 'tags', 'searchall', 'date', 'last', 'eventid', 'withAttachments', 'metadata', 'uuid', 'published', 'publish_timestamp', 'timestamp', 'enforceWarninglist', 'sgReferenceOnly', 'eventinfo', 'sharinggroup', 'excludeLocalTags', 'threat_level_id'),
'params' => array()
),
'addTag' => array(
@ -367,12 +367,7 @@ class RestResponseComponent extends Component
$controller = $controller === 'EventGraph' ? 'event_graph' : Inflector::tableize($controller);
foreach ($actions as $action => $data) {
if ($this->ACL->canUserAccess($user, $controller, $action)) {
$admin_routing = '';
if (substr($action, 0, 6) === 'admin_') {
$action = substr($action, 6);
$admin_routing = 'admin/';
}
$url = $this->baseurl . '/' . $admin_routing . $controller . '/' . $action;
$url = $this->generateUrl($controller, $action);
$result[$url] = $data;
}
}
@ -380,6 +375,25 @@ class RestResponseComponent extends Component
return $result;
}
/**
* @param array $user
* @return array
*/
public function getAccessibleApis(array $user)
{
$output = [];
foreach ($this->__descriptions as $controller => $actions) {
$controller = $controller === 'EventGraph' ? 'event_graph' : Inflector::tableize($controller);
foreach ($actions as $action => $data) {
if ($this->ACL->canUserAccess($user, $controller, $action)) {
$url = $this->generateUrl($controller, $action);
$output[$controller][$action] = $url;
}
}
}
return $output;
}
public function getAllApis($user)
{
$this->__setup();
@ -389,15 +403,10 @@ class RestResponseComponent extends Component
$controller = $controller === 'EventGraph' ? 'event_graph' : Inflector::tableize($controller);
foreach ($actions as $action => $data) {
if ($this->ACL->canUserAccess($user, $controller, $action)) {
$admin_routing = '';
if (substr($action, 0, 6) === 'admin_') {
$action = substr($action, 6);
$admin_routing = 'admin/';
}
$data['api_name'] = '[' . $controller . '] ' . $action;
$data['controller'] = $controller;
$data['action'] = $action;
$data['body'] = array();
$body = [];
$filter_types = array('mandatory', 'optional');
foreach ($filter_types as $filter_type) {
if (!empty($data[$filter_type])) {
@ -407,16 +416,16 @@ class RestResponseComponent extends Component
}
foreach ($filter_items as $filter) {
if ($filter === lcfirst($filter)) {
$data['body'][$filter] = $filter_type;
$body[$filter] = $filter_type;
} else {
$data['body'][$filter] = array($filter_type);
$body[$filter] = array($filter_type);
}
}
}
}
}
$data['body'] = json_encode($data['body'], JSON_PRETTY_PRINT);
$url = $this->baseurl . '/' . $admin_routing . $controller . '/' . $action;
$data['body'] = $body;
$url = $this->generateUrl($controller, $action);;
$data['url'] = $url;
if (!empty($data['params'])) {
foreach ($data['params'] as $param) {
@ -592,14 +601,14 @@ class RestResponseComponent extends Component
}
if ($response instanceof TmpFileTool) {
App::uses('CakeResponseFile', 'Tools');
$cakeResponse = new CakeResponseFile(['status' => $code, 'type' => $type]);
if ($this->signContents) {
$this->CryptographicKey = ClassRegistry::init('CryptographicKey');
$data = $response->intoString();
$headers['x-pgp-signature'] = base64_encode($this->CryptographicKey->signWithInstanceKey($data));
$cakeResponse = new CakeResponse(array('body' => $data, 'status' => $code, 'type' => $type));
$cakeResponse = new CakeResponse(['body' => $data, 'status' => $code, 'type' => $type]);
} else {
App::uses('CakeResponseFile', 'Tools');
$cakeResponse = new CakeResponseFile(['status' => $code, 'type' => $type]);
$cakeResponse->file($response);
}
} else {
@ -731,13 +740,8 @@ class RestResponseComponent extends Component
$scopes = array('Event', 'Attribute', 'Sighting');
foreach ($scopes as $scope) {
$this->{$scope} = ClassRegistry::init($scope);
$this->__descriptions[$scope]['restSearch'] = array(
'description' => $this->__descriptions[$scope]['restSearch']['description'],
'returnFormat' => array_keys($this->{$scope}->validFormats),
'mandatory' => $this->__descriptions[$scope]['restSearch']['mandatory'],
'optional' => $this->__descriptions[$scope]['restSearch']['optional'],
'params' => $this->__descriptions[$scope]['restSearch']['params']
);
$returnFormat = array_keys($this->{$scope}->validFormats);
$this->__descriptions[$scope]['restSearch']['returnFormat'] = $returnFormat;
}
$this->__configureFieldConstraints();
$this->__setupFieldsConstraint();
@ -1938,7 +1942,8 @@ class RestResponseComponent extends Component
if ($values === null) {
$tagModel = ClassRegistry::init("Tag");
$tags = $tagModel->find('column', array(
'fields' => array('Tag.name')
'fields' => array('Tag.name'),
'callbacks' => false,
));
$values = [];
foreach ($tags as $tag) {
@ -1963,19 +1968,40 @@ class RestResponseComponent extends Component
private function __overwriteAction($scope, $action, &$field) {
$field['values'] = array_keys(ClassRegistry::init("Log")->actionDefinitions);
}
private function __overwriteRoleId($scope, $action, &$field) {
$this->{$scope} = ClassRegistry::init("Role");
$roles = $this->{$scope}->find('list', array(
'fields' => array('id', 'name')
));
$field['values'] = [];
foreach ($roles as $id => $name) {
$field['values'][] = ['label' => $name, 'value' => $id];
private function __overwriteRoleId($scope, $action, &$field)
{
static $values;
if ($values === null) {
$roleModel = ClassRegistry::init("Role");
$roles = $roleModel->find('list', array(
'fields' => array('id', 'name')
));
$values = [];
foreach ($roles as $id => $name) {
$values[] = ['label' => $name, 'value' => $id];
}
}
$field['values'] = $values;
}
private function __overwriteSeen($scope, $action, &$field) {
if ($action == 'restSearch') {
$field['help'] = __('Seen within the last x amount of time, where x can be defined in days, hours, minutes (for example 5d or 12h or 30m)');
}
}
/**
* @param string $controller
* @param string $action
* @return string
*/
private function generateUrl($controller, $action)
{
$admin_routing = '';
if (substr($action, 0, 6) === 'admin_') {
$action = substr($action, 6);
$admin_routing = 'admin/';
}
return '/' . $admin_routing . $controller . '/' . $action;
}
}

View File

@ -1109,6 +1109,7 @@ class EventsController extends AppController
'eventid' => array('OR' => array(), 'NOT' => array()),
'date' => array('from' => "", 'until' => ""),
'eventinfo' => array('OR' => array(), 'NOT' => array()),
'all' => array('OR' => array(), 'NOT' => array()),
'threatlevel' => array('OR' => array(), 'NOT' => array()),
'distribution' => array('OR' => array(), 'NOT' => array()),
'sharinggroup' => array('OR' => array(), 'NOT' => array()),
@ -1187,6 +1188,7 @@ class EventsController extends AppController
'hasproposal' => __('Has proposal'),
'timestamp' => __('Last change at'),
'publishtimestamp' => __('Published at'),
'all' => __('Search in all fields'),
];
if ($this->_isSiteAdmin()) {
@ -1402,6 +1404,8 @@ class EventsController extends AppController
$advancedFiltering = $this->__checkIfAdvancedFiltering($filters);
$this->set('advancedFilteringActive', $advancedFiltering['active'] ? 1 : 0);
$this->set('advancedFilteringActiveRules', $advancedFiltering['activeRules']);
$this->set('mayModify', $this->__canModifyEvent($event));
$this->set('mayPublish', $this->__canPublishEvent($event));
$this->response->disableCache();
// Remove `focus` attribute from URI
@ -3211,7 +3215,8 @@ class EventsController extends AppController
'order' => 'Event.timestamp DESC',
));
$this->loadModel('Job');
foreach ($this->Event->export_types as $k => $type) {
$exportTypes = $this->Event->exportTypes();
foreach ($exportTypes as $k => $type) {
if ($type['requiresPublished']) {
$tempNewestEvent = $newestEventPublished;
} else {
@ -3235,10 +3240,10 @@ class EventsController extends AppController
if (!$file->readable()) {
if (empty($tempNewestEvent)) {
$lastModified = 'No valid events';
$this->Event->export_types[$k]['recommendation'] = 0;
$exportTypes[$k]['recommendation'] = 0;
} else {
$lastModified = 'N/A';
$this->Event->export_types[$k]['recommendation'] = 1;
$exportTypes[$k]['recommendation'] = 1;
}
} else {
$filesize = $file->size();
@ -3247,32 +3252,31 @@ class EventsController extends AppController
$filesize_unit_index++;
$filesize = $filesize / 1024;
}
$this->Event->export_types[$k]['filesize'] = round($filesize, 1) . $filesize_units[$filesize_unit_index];
$exportTypes[$k]['filesize'] = round($filesize, 1) . $filesize_units[$filesize_unit_index];
$fileChange = $file->lastChange();
$lastModified = $this->__timeDifference($now, $fileChange);
if (empty($tempNewestEvent) || $fileChange > $tempNewestEvent['Event']['timestamp']) {
if (empty($tempNewestEvent)) {
$lastModified = 'No valid events';
}
$this->Event->export_types[$k]['recommendation'] = 0;
$exportTypes[$k]['recommendation'] = 0;
} else {
$this->Event->export_types[$k]['recommendation'] = 1;
$exportTypes[$k]['recommendation'] = 1;
}
}
$this->Event->export_types[$k]['lastModified'] = $lastModified;
$exportTypes[$k]['lastModified'] = $lastModified;
if (!empty($job)) {
$this->Event->export_types[$k]['job_id'] = $job['Job']['id'];
$this->Event->export_types[$k]['progress'] = $job['Job']['progress'];
$exportTypes[$k]['job_id'] = $job['Job']['id'];
$exportTypes[$k]['progress'] = $job['Job']['progress'];
} else {
$this->Event->export_types[$k]['job_id'] = -1;
$this->Event->export_types[$k]['progress'] = 0;
$exportTypes[$k]['job_id'] = -1;
$exportTypes[$k]['progress'] = 0;
}
}
}
$this->loadModel('Attribute');
$this->set('sigTypes', array_keys($this->Attribute->typeDefinitions));
$this->set('export_types', $this->Event->export_types);
$this->set('sigTypes', array_keys($this->Event->Attribute->typeDefinitions));
$this->set('export_types', $exportTypes);
}
public function downloadExport($type, $extra = null)
@ -3289,8 +3293,9 @@ class EventsController extends AppController
if ($extra != null) {
$extra = '_' . $extra;
}
$this->response->type($this->Event->export_types[$type]['extension']);
$path = 'tmp/cached_exports/' . $type . DS . 'misp.' . strtolower($this->Event->export_types[$type]['type']) . $extra . '.' . $org . $this->Event->export_types[$type]['extension'];
$exportType = $this->Event->exportTypes()[$type];
$this->response->type($exportType['extension']);
$path = 'tmp/cached_exports/' . $type . DS . 'misp.' . strtolower($exportType['type']) . $extra . '.' . $org . $exportType['extension'];
$this->response->file($path, array('download' => true));
}
@ -3920,17 +3925,18 @@ class EventsController extends AppController
*/
public function freeTextImport($id, $adhereToWarninglists = false, $returnMetaAttributes = false)
{
$this->request->allowMethod(['post', 'get']);
$event = $this->Event->fetchSimpleEvent($this->Auth->user(), $id);
if (empty($event)) {
throw new MethodNotAllowedException(__('Invalid event.'));
throw new NotFoundException(__('Invalid event.'));
}
$this->set('event_id', $event['Event']['id']);
if ($this->request->is('get')) {
$this->layout = 'ajax';
$this->request->data['Attribute']['event_id'] = $event['Event']['id'];
}
if ($this->request->is('post')) {
} else if ($this->request->is('post')) {
App::uses('ComplexTypeTool', 'Tools');
$complexTypeTool = new ComplexTypeTool();
$this->loadModel('Warninglist');
@ -3944,16 +3950,16 @@ class EventsController extends AppController
if (isset($this->request->data['Attribute']['adhereToWarninglists'])) {
$adhereToWarninglists = $this->request->data['Attribute']['adhereToWarninglists'];
}
$resultArray = $complexTypeTool->checkComplexRouter($this->request->data['Attribute']['value'], 'freetext');
foreach ($resultArray as $key => $r) {
$temp = array();
foreach ($r['types'] as $type) {
$temp[$type] = $type;
}
$resultArray[$key]['types'] = $temp;
}
$resultArray = $complexTypeTool->checkFreeText($this->request->data['Attribute']['value']);
if ($this->_isRest()) {
// Keep this 'types' format for rest response, but it is not necessary for UI
foreach ($resultArray as $key => $r) {
$temp = array();
foreach ($r['types'] as $type) {
$temp[$type] = $type;
}
$resultArray[$key]['types'] = $temp;
}
if ($returnMetaAttributes || !empty($this->request->data['Attribute']['returnMetaAttributes'])) {
return $this->RestResponse->viewData($resultArray, $this->response->type());
} else {
@ -3967,7 +3973,6 @@ class EventsController extends AppController
}
}
$this->Event->Attribute->fetchRelated($this->Auth->user(), $resultArray);
$resultArray = array_values($resultArray);
$typeCategoryMapping = array();
foreach ($this->Event->Attribute->categoryDefinitions as $k => $cat) {
foreach ($cat['types'] as $type) {
@ -3987,15 +3992,10 @@ class EventsController extends AppController
$this->set('mayModify', $this->__canModifyEvent($event));
$this->set('typeDefinitions', $this->Event->Attribute->typeDefinitions);
$this->set('typeCategoryMapping', $typeCategoryMapping);
foreach ($typeCategoryMapping as $k => $v) {
$typeCategoryMapping[$k] = array_values($v);
}
$this->set('mapping', $typeCategoryMapping);
$this->set('resultArray', $resultArray);
$this->set('importComment', '');
$this->set('title_for_layout', __('Freetext Import Results'));
$this->set('title', __('Freetext Import Results'));
$this->loadModel('Warninglist');
$this->set('missingTldLists', $this->Warninglist->missingTldLists());
$this->render('resolved_attributes');
}
@ -4038,19 +4038,17 @@ class EventsController extends AppController
public function saveFreeText($id)
{
if (!$this->request->is('post')) {
throw new MethodNotAllowedException('This endpoint requires a POST request.');
}
$this->request->allowMethod(['post']);
$event = $this->Event->fetchSimpleEvent($this->Auth->user(), $id);
if (!$event) {
throw new NotFoundException(__('Invalid event.'));
}
$this->Event->insertLock($this->Auth->user(), $id);
$attributes = json_decode($this->request->data['Attribute']['JsonObject'], true);
$default_comment = $this->request->data['Attribute']['default_comment'];
$attributes = $this->_jsonDecode($this->request->data['Attribute']['JsonObject']);
$defaultComment = $this->request->data['Attribute']['default_comment'];
$proposals = !$this->__canModifyEvent($event) || (isset($this->request->data['Attribute']['force']) && $this->request->data['Attribute']['force']);
$flashMessage = $this->Event->processFreeTextDataRouter($this->Auth->user(), $attributes, $id, $default_comment, $proposals);
$flashMessage = $this->Event->processFreeTextDataRouter($this->Auth->user(), $attributes, $id, $defaultComment, $proposals);
$this->Flash->info($flashMessage);
if ($this->request->is('ajax')) {
@ -6139,7 +6137,7 @@ class EventsController extends AppController
/**
* @param array $event
* @return CakeResponseTmp
* @return CakeResponseFile
* @throws Exception
*/
private function __restResponse(array $event)
@ -6171,23 +6169,24 @@ class EventsController extends AppController
public function protect($id)
{
$this->__toggleProtect($id, true);
return $this->__toggleProtect($id, true);
}
public function unprotect($id)
{
$this->__toggleProtect($id, false);
return $this->__toggleProtect($id, false);
}
/**
* @param string|int $id Event ID or UUID
* @param bool $protect
* @return CakeResponse|void
* @throws Exception
*/
private function __toggleProtect($id, $protect)
{
$id = $this->Toolbox->findIdByUuid($this->Event, $id);
$event = $this->Event->fetchSimpleEvent($this->Auth->user(), $id, ['contain' => ['Orgc']]);
if (
(!$this->_isSiteAdmin && $event['Event']['orgc_id'] !== $this->Auth->user('org_id')) ||
!$event ||
!$this->__canModifyEvent($event)
) {
$event = $this->Event->fetchSimpleEvent($this->Auth->user(), $id);
if (empty($event) || !$this->__canModifyEvent($event)) {
throw new NotFoundException(__('Invalid event'));
}
if ($this->request->is('post')) {
@ -6197,7 +6196,7 @@ class EventsController extends AppController
if ($this->Event->save($event)) {
$message = __('Event switched to %s mode.', $protect ? __('protected') : __('unprotected'));
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('events', $protect ? 'protect' : 'unprotect', $id, false, $message);
return $this->RestResponse->saveSuccessResponse('events', $protect ? 'protect' : 'unprotect', $event['Event']['id'], false, $message);
} else {
$this->Flash->success($message);
$this->redirect(['controller' => 'events', 'action' => 'view', $id]);
@ -6205,14 +6204,14 @@ class EventsController extends AppController
} else {
$message = __('Something went wrong - could not switch event to %s mode.', $protect ? __('protected') : __('unprotected'));
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Events', $protect ? 'protect' : 'unprotect', false, $message, $this->response->type());
return $this->RestResponse->saveFailResponse('Events', $protect ? 'protect' : 'unprotect', $event['Event']['id'], $message);
} else {
$this->Flash->error($message);
$this->redirect(['controller' => 'events', 'action' => 'view', $id]);
$this->redirect(['controller' => 'events', 'action' => 'view', $event['Event']['id']]);
}
}
} else {
$this->set('id', $id);
$this->set('id', $event['Event']['id']);
$this->set('title', $protect ? __('Protect event') : __('Remove event protection'));
$this->set(
'question',

View File

@ -298,6 +298,9 @@ class FeedsController extends AppController
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->loadModel('Server');
$allTypes = $this->Server->getAllTypes();
$dropdownData = [
'orgs' => $this->Event->Orgc->find('list', array(
'fields' => array('id', 'name'),
@ -309,9 +312,12 @@ class FeedsController extends AppController
'distributionLevels' => $distributionLevels,
'inputSources' => $inputSources
];
$this->set('allAttributeTypes', $allTypes['attribute']);
$this->set('allObjectTypes', $allTypes['object']);
$this->set(compact('dropdownData'));
$this->set('defaultPullRules', json_encode(Feed::DEFAULT_FEED_PULL_RULES));
$this->set('menuData', array('menuList' => 'feeds', 'menuItem' => 'add'));
$this->set('pull_scope', 'feed');
}
private function __checkRegex($pattern)
@ -346,10 +352,14 @@ class FeedsController extends AppController
'delete_local_file',
'lookup_visible',
'headers',
'orgc_id'
'orgc_id',
'fixed_event'
],
'afterFind' => function (array $feed) {
$feed['Feed']['settings'] = json_decode($feed['Feed']['settings'], true);
if ($feed['Feed']['source_format'] == 'misp' && empty($feed['Feed']['rules'])) {
$feed['Feed']['rules'] = json_encode(Feed::DEFAULT_FEED_PULL_RULES);
}
return $feed;
},
@ -437,6 +447,12 @@ class FeedsController extends AppController
$tags = $this->Event->EventTag->Tag->find('list', array('fields' => array('Tag.name'), 'order' => array('lower(Tag.name) asc')));
$tags[0] = 'None';
$this->loadModel('Server');
$allTypes = $this->Server->getAllTypes();
$this->set('allAttributeTypes', $allTypes['attribute']);
$this->set('allObjectTypes', $allTypes['object']);
$this->set('supportedUrlparams', Feed::SUPPORTED_URL_PARAM_FILTERS);
$dropdownData = [
'orgs' => $this->Event->Orgc->find('list', array(
'fields' => array('id', 'name'),
@ -458,6 +474,7 @@ class FeedsController extends AppController
if(!empty($this->request->data['Feed']['rules'])){
$this->request->data['Feed']['pull_rules'] = $this->request->data['Feed']['rules'];
}
$this->set('pull_scope', 'feed');
$this->render('add');
}

View File

@ -573,21 +573,21 @@ class ObjectsController extends AppController
public function fetchViewValue($id, $field = null)
{
$validFields = array('timestamp', 'comment', 'distribution', 'first_seen', 'last_seen');
if (!isset($field) || !in_array($field, $validFields)) {
if (!isset($field) || !in_array($field, $validFields, true)) {
throw new MethodNotAllowedException('Invalid field requested.');
}
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException('This function can only be accessed via AJAX.');
}
$params = array(
'conditions' => array('Object.id' => $id),
'fields' => array('id', 'distribution', 'event_id', $field),
'contain' => array(
'Event' => array(
'fields' => array('distribution', 'id', 'org_id'),
)
),
'flatten' => 1
'conditions' => array('Object.id' => $id),
'fields' => array('id', 'distribution', 'event_id', $field),
'contain' => array(
'Event' => array(
'fields' => array('distribution', 'id', 'org_id'),
)
),
'flatten' => 1
);
$object = $this->MispObject->fetchObjectSimple($this->Auth->user(), $params);
if (empty($object)) {
@ -595,10 +595,11 @@ class ObjectsController extends AppController
}
$object = $object[0];
$result = $object['Object'][$field];
if ($field == 'distribution') {
$result=$this->MispObject->shortDist[$result];
if ($field === 'distribution') {
$result = $this->MispObject->shortDist[$result];
}
$this->set('value', $result);
$this->set('field', $field);
$this->layout = 'ajax';
$this->render('ajax/objectViewFieldForm');
}

View File

@ -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');

View File

@ -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('/');

View File

@ -1,7 +1,9 @@
<?php
App::uses('AppController', 'Controller');
/**
* @property RestClientHistory $RestClientHistory
*/
class RestClientHistoryController extends AppController
{
public $components = array(
@ -37,19 +39,16 @@ class RestClientHistoryController extends AppController
}
if ($this->_isRest()) {
$list = $this->RestClientHistory->find('all', $params);
} else {
$this->paginate = array_merge($this->paginate, $params);
$list = $this->paginate();
}
if ($this->_isRest()) {
return $this->RestResponse->viewData($list, $this->response->type());
} else {
$this->set('bookmarked', $bookmarked);
$this->set('list', $list);
$this->layout = false;
$this->autoRender = false;
$this->render('index');
}
$this->paginate = array_merge($this->paginate, $params);
$list = $this->paginate();
$this->set('bookmarked', $bookmarked);
$this->set('list', array_column($list, 'RestClientHistory'));
$this->layout = false;
$this->autoRender = false;
$this->render('index');
}
public function delete($id)

View File

@ -39,7 +39,6 @@ class ServersController extends AppController
$this->Auth->allow(['cspReport']); // cspReport must work without authentication
parent::beforeFilter();
$this->Security->unlockedActions[] = 'getApiInfo';
$this->Security->unlockedActions[] = 'cspReport';
// permit reuse of CSRF tokens on some pages.
switch ($this->request->params['action']) {
@ -443,20 +442,7 @@ class ServersController extends AppController
$allOrgs[] = array('id' => $o['Organisation']['id'], 'name' => $o['Organisation']['name']);
}
$allTypes = [];
$this->loadModel('Attribute');
$this->loadModel('ObjectTemplate');
$objects = $this->ObjectTemplate->find('all', [
'recursive' => -1,
'fields' => ['uuid', 'name'],
'group' => ['uuid', 'name'],
]);
$allTypes = [
'attribute' => array_unique(Hash::extract(Hash::extract($this->Attribute->categoryDefinitions, '{s}.types'), '{n}.{n}')),
'object' => Hash::map($objects, '{n}.ObjectTemplate', function ($item) {
return ['id' => $item['uuid'], 'name' => sprintf('%s (%s)', $item['name'], $item['uuid'])];
})
];
$allTypes = $this->Server->getAllTypes();
$this->set('host_org_id', Configure::read('MISP.host_org_id'));
$this->set('organisationOptions', $organisationOptions);
@ -468,6 +454,7 @@ class ServersController extends AppController
$this->set('allTags', $this->__getTags());
$this->set('host_org_id', Configure::read('MISP.host_org_id'));
$this->set('pull_scope', 'server');
$this->render('edit');
}
}
@ -641,20 +628,7 @@ class ServersController extends AppController
$allOrgs[] = array('id' => $o['Organisation']['id'], 'name' => $o['Organisation']['name']);
}
$allTypes = [];
$this->loadModel('Attribute');
$this->loadModel('ObjectTemplate');
$objects = $this->ObjectTemplate->find('all', [
'recursive' => -1,
'fields' => ['uuid', 'name'],
'group' => ['uuid', 'name'],
]);
$allTypes = [
'attribute' => array_unique(Hash::extract(Hash::extract($this->Attribute->categoryDefinitions, '{s}.types'), '{n}.{n}')),
'object' => Hash::map($objects, '{n}.ObjectTemplate', function ($item) {
return ['id' => $item['uuid'], 'name' => sprintf('%s (%s)', $item['name'], $item['uuid'])];
})
];
$allTypes = $this->Server->getAllTypes();
$oldRemoteSetting = 0;
if (!$this->Server->data['RemoteOrg']['local']) {
@ -675,6 +649,7 @@ class ServersController extends AppController
$this->set('server', $s);
$this->set('id', $id);
$this->set('host_org_id', Configure::read('MISP.host_org_id'));
$this->set('pull_scope', 'server');
}
}
@ -1996,280 +1971,6 @@ class ServersController extends AppController
return $this->RestResponse->viewData(array('uuid' => Configure::read('MISP.uuid')), $this->response->type());
}
public function rest()
{
$allValidApis = $this->RestResponse->getAllApis($this->Auth->user());
$allValidApisFieldsContraint = $this->RestResponse->getAllApisFieldsConstraint($this->Auth->user());
if ($this->request->is('post')) {
$request = $this->request->data;
if (!empty($request['Server'])) {
$request = $this->request->data['Server'];
}
$curl = '';
$python = '';
try {
$result = $this->__doRestQuery($request, $curl, $python);
$this->set('curl', $curl);
$this->set('python', $python);
if (!$result) {
$this->Flash->error('Something went wrong. Make sure you set the http method, body (when sending POST requests) and URL correctly.');
} else {
$this->set('data', $result);
}
} catch (Exception $e) {
$this->Flash->error(__('Something went wrong. %s', $e->getMessage()));
}
}
$header = sprintf(
"Authorization: %s \nAccept: application/json\nContent-type: application/json",
__('YOUR_API_KEY')
);
$this->set('header', $header);
$this->set('allValidApis', $allValidApis);
// formating for optgroup
$allValidApisFormated = array();
foreach ($allValidApis as $endpoint_url => $endpoint_data) {
$allValidApisFormated[$endpoint_data['controller']][] = array('url' => $endpoint_url, 'action' => $endpoint_data['action']);
}
$this->set('allValidApisFormated', $allValidApisFormated);
$this->set('allValidApisFieldsContraint', $allValidApisFieldsContraint);
}
/**
* @param array $request
* @param string $curl
* @param string $python
* @return array|false
*/
private function __doRestQuery(array $request, &$curl = false, &$python = false)
{
App::uses('SyncTool', 'Tools');
$params = array();
$logHeaders = $request['header'];
if (!empty(Configure::read('Security.advanced_authkeys'))) {
$logHeaders = explode("\n", $request['header']);
foreach ($logHeaders as $k => $header) {
if (strpos($header, 'Authorization') !== false) {
$logHeaders[$k] = 'Authorization: ' . __('YOUR_API_KEY');
}
}
$logHeaders = implode("\n", $logHeaders);
}
if (empty($request['body'])) {
$historyBody = '';
} else if (strlen($request['body']) > 65535) {
$historyBody = ''; // body is too long to save into history table
} else {
$historyBody = $request['body'];
}
$rest_history_item = array(
'org_id' => $this->Auth->user('org_id'),
'user_id' => $this->Auth->user('id'),
'headers' => $logHeaders,
'body' => $historyBody,
'url' => $request['url'],
'http_method' => $request['method'],
'use_full_path' => empty($request['use_full_path']) ? false : $request['use_full_path'],
'show_result' => $request['show_result'],
'skip_ssl' => $request['skip_ssl_validation'],
'bookmark' => $request['bookmark'],
'bookmark_name' => $request['name'],
'timestamp' => time(),
);
if (!empty($request['url'])) {
if (empty($request['use_full_path']) || empty(Configure::read('Security.rest_client_enable_arbitrary_urls'))) {
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
$url = empty(Configure::read('Security.rest_client_baseurl')) ? (Configure::read('MISP.baseurl') . $path) : (Configure::read('Security.rest_client_baseurl') . $path);
unset($request['url']);
} else {
$url = $request['url'];
}
} else {
throw new InvalidArgumentException('URL not set.');
}
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
$params['ssl_verify_host'] = false;
$params['ssl_verify_peer_name'] = false;
$params['ssl_allow_self_signed'] = true;
}
$params['timeout'] = 300;
App::uses('HttpSocket', 'Network/Http');
$HttpSocket = new HttpSocket($params);
$temp_headers = empty($request['header']) ? [] : explode("\n", $request['header']);
$request['header'] = array(
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'MISP REST Client',
);
foreach ($temp_headers as $header) {
$header = explode(':', $header);
$header[0] = trim($header[0]);
$header[1] = trim($header[1]);
$request['header'][$header[0]] = $header[1];
}
$start = microtime(true);
if (
!empty($request['method']) &&
$request['method'] === 'GET'
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('get', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->get($url, false, array('header' => $request['header']));
} elseif (
!empty($request['method']) &&
$request['method'] === 'POST' &&
!empty($request['body'])
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('post', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->post($url, $request['body'], array('header' => $request['header']));
} elseif (
!empty($request['method']) &&
$request['method'] === 'DELETE'
) {
if ($curl !== false) {
$curl = $this->__generateCurlQuery('delete', $request, $url);
}
if ($python !== false) {
$python = $this->__generatePythonScript($request, $url);
}
$response = $HttpSocket->delete($url, false, array('header' => $request['header']));
} else {
return false;
}
$viewData = [
'duration' => round((microtime(true) - $start) * 1000, 2) . ' ms',
'url' => $url,
'code' => $response->code,
'headers' => $response->headers,
];
if (!empty($request['show_result'])) {
$viewData['data'] = $response->body;
} else {
if ($response->isOk()) {
$viewData['data'] = 'Success.';
} else {
$viewData['data'] = 'Something went wrong.';
}
}
$rest_history_item['outcome'] = $response->code;
$this->loadModel('RestClientHistory');
$this->RestClientHistory->create();
$this->RestClientHistory->save($rest_history_item);
$this->RestClientHistory->cleanup($this->Auth->user('id'));
return $viewData;
}
private function __generatePythonScript($request, $url)
{
$slashCounter = 0;
$baseurl = '';
$relative = '';
$verifyCert = ($url[4] === 's') ? 'True' : 'False';
for ($i = 0; $i < strlen($url); $i++) {
//foreach ($url as $url[$i]) {
if ($url[$i] === '/') {
$slashCounter += 1;
if ($slashCounter == 3) {
continue;
}
}
if ($slashCounter < 3) {
$baseurl .= $url[$i];
} else {
$relative .= $url[$i];
}
}
$python_script =
sprintf(
'misp_url = \'%s\'
misp_key = \'%s\'
misp_verifycert = %s
relative_path = \'%s\'
body = %s
from pymisp import ExpandedPyMISP
misp = ExpandedPyMISP(misp_url, misp_key, misp_verifycert)
misp.direct_call(relative_path, body)
',
$baseurl,
$request['header']['Authorization'],
$verifyCert,
$relative,
(empty($request['body']) ? 'None' : $request['body'])
);
return $python_script;
}
private function __generateCurlQuery($type, $request, $url)
{
if ($type === 'get') {
$curl = sprintf(
'curl \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s %s',
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
} else {
$curl = sprintf(
'curl \%s -d \'%s\' \%s -H "Authorization: %s" \%s -H "Accept: %s" \%s -H "Content-type: %s" \%s -X POST %s',
PHP_EOL,
json_encode(json_decode($request['body'])),
PHP_EOL,
$request['header']['Authorization'],
PHP_EOL,
$request['header']['Accept'],
PHP_EOL,
$request['header']['Content-Type'],
PHP_EOL,
$url
);
}
return $curl;
}
public function getApiInfo()
{
$relative_path = $this->request->data['url'];
$result = $this->RestResponse->getApiInfo($relative_path);
if ($this->_isRest()) {
if (!empty($result)) {
$result['api_info'] = $result;
}
return $this->RestResponse->viewData($result, $this->response->type());
} else {
if (empty($result)) {
return $this->RestResponse->viewData('&nbsp;', $this->response->type());
}
$this->layout = false;
$this->autoRender = false;
$this->set('api_info', $result);
$this->render('ajax/get_api_info');
}
}
public function cache($id = 'all')
{
if (Configure::read('MISP.background_jobs')) {
@ -2525,17 +2226,6 @@ misp.direct_call(relative_path, body)
return new CakeResponse(['status' => 204]);
}
public function viewDeprecatedFunctionUse()
{
$data = $this->Deprecation->getDeprecatedAccessList($this->Server);
if ($this->_isRest()) {
return $this->RestResponse->viewData($data, $this->response->type());
} else {
$this->layout = false;
$this->set('data', $data);
}
}
/**
* List all tags for the rule picker.
*
@ -2590,9 +2280,6 @@ misp.direct_call(relative_path, body)
return $this->RestResponse->viewData($syncFilteringRules);
}
public function openapi() {
}
public function pruneDuplicateUUIDs()
{
if (!$this->request->is('post')) {
@ -2762,4 +2449,13 @@ misp.direct_call(relative_path, body)
}
return $this->RestResponse->viewData($users, $this->response->type());
}
/**
* @deprecated
* @return void
*/
public function rest()
{
$this->redirect(['controller' => 'api', 'action' => 'rest']);
}
}

View File

@ -183,27 +183,17 @@ class TaxonomiesController extends AppController
public function enable($id)
{
if (!$this->_isSiteAdmin() || !$this->request->is('Post')) {
throw new MethodNotAllowedException(__('You don\'t have permission to do that.'));
}
$this->request->allowMethod(['post']);
$taxonomy = $this->Taxonomy->find('first', array(
'recursive' => -1,
'conditions' => array('Taxonomy.id' => $id),
));
$taxonomy['Taxonomy']['enabled'] = true;
$this->Taxonomy->save($taxonomy);
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Taxonomy',
'model_id' => $id,
'email' => $this->Auth->user('email'),
'action' => 'enable',
'user_id' => $this->Auth->user('id'),
'title' => 'Taxonomy enabled',
'change' => $taxonomy['Taxonomy']['namespace'] . ' - enabled',
));
$this->__log('enable', $id, 'Taxonomy enabled', $taxonomy['Taxonomy']['namespace'] . ' - enabled');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Taxonomy', 'enable', $id, $this->response->type());
} else {
@ -214,28 +204,18 @@ class TaxonomiesController extends AppController
public function disable($id)
{
if (!$this->_isSiteAdmin() || !$this->request->is('Post')) {
throw new MethodNotAllowedException(__('You don\'t have permission to do that.'));
}
$this->request->allowMethod(['post']);
$taxonomy = $this->Taxonomy->find('first', array(
'recursive' => -1,
'conditions' => array('Taxonomy.id' => $id),
'recursive' => -1,
'conditions' => array('Taxonomy.id' => $id),
));
$this->Taxonomy->disableTags($id);
$taxonomy['Taxonomy']['enabled'] = 0;
$this->Taxonomy->save($taxonomy);
$this->Log = ClassRegistry::init('Log');
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Taxonomy',
'model_id' => $id,
'email' => $this->Auth->user('email'),
'action' => 'disable',
'user_id' => $this->Auth->user('id'),
'title' => 'Taxonomy disabled',
'change' => $taxonomy['Taxonomy']['namespace'] . ' - disabled',
));
$this->__log('disable', $id, 'Taxonomy disabled', $taxonomy['Taxonomy']['namespace'] . ' - disabled');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Taxonomy', 'disable', $id, $this->response->type());
} else {
@ -246,9 +226,8 @@ class TaxonomiesController extends AppController
public function import()
{
if (!$this->request->is('post')) {
throw new MethodNotAllowedException('This endpoint requires a POST request.');
}
$this->request->allowMethod(['post']);
try {
$id = $this->Taxonomy->import($this->request->data);
return $this->view($id);
@ -260,7 +239,6 @@ class TaxonomiesController extends AppController
public function update()
{
$result = $this->Taxonomy->update();
$this->Log = ClassRegistry::init('Log');
$fails = 0;
$successes = 0;
if (!empty($result)) {
@ -271,50 +249,19 @@ class TaxonomiesController extends AppController
} else {
$change = $success['namespace'] . ' v' . $success['new'] . ' installed';
}
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Taxonomy',
'model_id' => $id,
'email' => $this->Auth->user('email'),
'action' => 'update',
'user_id' => $this->Auth->user('id'),
'title' => 'Taxonomy updated',
'change' => $change,
));
$this->__log('update', $id, 'Taxonomy updated', $change);
$successes++;
}
}
if (isset($result['fails'])) {
foreach ($result['fails'] as $id => $fail) {
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Taxonomy',
'model_id' => $id,
'email' => $this->Auth->user('email'),
'action' => 'update',
'user_id' => $this->Auth->user('id'),
'title' => 'Taxonomy failed to update',
'change' => $fail['namespace'] . ' could not be installed/updated. Error: ' . $fail['fail'],
));
$this->__log('update', $id, 'Taxonomy failed to update', $fail['namespace'] . ' could not be installed/updated. Error: ' . $fail['fail']);
$fails++;
}
}
} else {
$this->Log->create();
$this->Log->save(array(
'org' => $this->Auth->user('Organisation')['name'],
'model' => 'Taxonomy',
'model_id' => 0,
'email' => $this->Auth->user('email'),
'action' => 'update',
'user_id' => $this->Auth->user('id'),
'title' => 'Taxonomy update (nothing to update)',
'change' => 'Executed an update of the taxonomy library, but there was nothing to update.',
));
$this->__log('update', 0, 'Taxonomy update (nothing to update)', 'Executed an update of the taxonomy library, but there was nothing to update.');
}
$message = '';
if ($successes == 0 && $fails == 0) {
$flashType = 'info';
$message = __('All taxonomy libraries are up to date already.');
@ -338,9 +285,6 @@ class TaxonomiesController extends AppController
public function addTag($taxonomy_id = false)
{
if ((!$this->_isSiteAdmin() && !$this->userRole['perm_tagger'])) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
if ($this->request->is('get')) {
if (empty($taxonomy_id) && !empty($this->request->params['named']['taxonomy_id'])) {
$taxonomy_id = $this->request->params['named']['taxonomy_id'];
@ -391,9 +335,8 @@ class TaxonomiesController extends AppController
public function hideTag($taxonomy_id = false)
{
if ((!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) || !$this->request->is('post')) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
$this->request->allowMethod(['post']);
if ($taxonomy_id) {
$result = $this->Taxonomy->hideTags($taxonomy_id);
} else {
@ -421,9 +364,8 @@ class TaxonomiesController extends AppController
public function unhideTag($taxonomy_id = false)
{
if ((!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) || !$this->request->is('post')) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
$this->request->allowMethod(['post']);
if ($taxonomy_id) {
$result = $this->Taxonomy->unhideTags($taxonomy_id);
} else {
@ -451,9 +393,6 @@ class TaxonomiesController extends AppController
public function disableTag($taxonomy_id = false)
{
if ((!$this->_isSiteAdmin() && !$this->userRole['perm_tagger'])) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
if ($this->request->is('get')) {
if (empty($taxonomy_id) && !empty($this->request->params['named']['taxonomy_id'])) {
$taxonomy_id = $this->request->params['named']['taxonomy_id'];
@ -559,6 +498,21 @@ class TaxonomiesController extends AppController
$this->render('ajax/toggle_required');
}
/**
* @param string $action
* @param int $modelId
* @param string $title
* @param string $change
* @return void
* @throws Exception
*/
private function __log($action, $modelId, $title, $change)
{
/** @var Log $log */
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), $action, 'Taxonomy', $modelId, $title, $change);
}
/**
* Attach tag counts.
* @param array $taxonomies

View File

@ -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']);

View File

@ -40,9 +40,6 @@ class ComplexTypeTool
128 => array('single' => array('sha512'), 'composite' => array('filename|sha512'))
);
// algorithms to run through in order, without Hashes that are checked separately
const CHECKS = array('Email', 'IP', 'DomainOrFilename', 'SimpleRegex', 'AS', 'BTC');
private $__tlds = null;
public static function refangValue($value, $type)
@ -179,6 +176,9 @@ class ComplexTypeTool
continue;
}
foreach ($row as $elementPos => $element) {
if (empty($element)) {
continue;
}
if (empty($values) || in_array(($elementPos + 1), $values)) {
$element = trim($element, " \t\n\r\0\x0B\"\'");
if (empty($element)) {
@ -198,23 +198,28 @@ class ComplexTypeTool
return $iocArray;
}
public function checkFreeText($input, $settings = array())
/**
* @param string $input
* @param array $settings
* @return array
*/
public function checkFreeText($input, array $settings = [])
{
$charactersToTrim = '\'".,() ' . "\t\n\r\0\x0B"; // custom + default PHP trim
$input = str_replace("\xc2\xa0", ' ', $input); // non breaking space to normal space
$input = preg_replace('/\p{C}+/u', ' ', $input);
$iocArray = preg_split("/\r\n|\n|\r|\s|\s+|,|\<|\>|;/", $input);
preg_match_all('/\"([^\"]*)\"/', $input, $matches);
foreach ($matches[1] as $match) {
if ($match !== '') {
$iocArray[] = $match;
}
}
preg_match_all('/\"([^\"]*)\"/', $input, $matches);
foreach ($matches[1] as $match) {
if ($match !== '') {
$iocArray[] = $match;
}
}
unset($matches);
$resultArray = [];
foreach ($iocArray as $ioc) {
$ioc = trim($ioc, $charactersToTrim);
$ioc = trim($ioc, '\'".,() ' . "\t\n\r\0\x0B"); // custom + default PHP trim
if (empty($ioc)) {
continue;
}
@ -251,23 +256,37 @@ class ComplexTypeTool
];
}
$input = array('raw' => $raw_input);
$input = ['raw' => $raw_input];
// Check hashes before refang and port extracting, it is not necessary for hashes. This speedups parsing
// freetexts or CSVs with a lot of hashes.
$hashes = $this->__checkForHashes($input);
if ($hashes) {
return $hashes;
if ($result = $this->__checkForHashes($input)) {
return $result;
}
$input = $this->__refangInput($input);
$input = $this->__extractPort($input);
foreach (self::CHECKS as $check) {
$result = $this->{'__checkFor' . $check}($input);
if ($result) {
return $result;
}
// Check email before port extracting, it is not necessary for email. This speedups parsing
// freetexts or CSVs with a lot of emails.
if ($result = $this->__checkForEmail($input)) {
return $result;
}
$input = $this->__extractPort($input);
if ($result = $this->__checkForIP($input)) {
return $result;
}
if ($result = $this->__checkForDomainOrFilename($input)) {
return $result;
}
if ($result = $this->__checkForSimpleRegex($input)) {
return $result;
}
if ($result = $this->__checkForAS($input)) {
return $result;
}
if ($result = $this->__checkForBTC($input)) {
return $result;
}
return false;
}
@ -290,7 +309,12 @@ class ComplexTypeTool
// quick filter for an @ to see if we should validate a potential e-mail address
if (strpos($input['refanged'], '@') !== false) {
if (filter_var($input['refanged'], FILTER_VALIDATE_EMAIL)) {
return array('types' => array('email', 'email-src', 'email-dst', 'target-email', 'whois-registrant-email'), 'to_ids' => true, 'default_type' => 'email-src', 'value' => $input['refanged']);
return [
'types' => array('email', 'email-src', 'email-dst', 'target-email', 'whois-registrant-email'),
'to_ids' => true,
'default_type' => 'email-src',
'value' => $input['refanged'],
];
}
}
return false;
@ -356,17 +380,17 @@ class ComplexTypeTool
private function __refangInput($input)
{
$input['refanged'] = $input['raw'];
$refanged = $input['raw'];
foreach (self::REFANG_REGEX_TABLE as $regex) {
$input['refanged'] = preg_replace($regex['from'], $regex['to'], $input['refanged']);
$refanged = preg_replace($regex['from'], $regex['to'], $refanged);
}
$input['refanged'] = rtrim($input['refanged'], ".");
$refanged = rtrim($refanged, ".");
$input['refanged'] = preg_replace_callback(
'/\[.\]/',
function ($matches) {
return trim($matches[0], '[]');
},
$input['refanged']
$refanged
);
return $input;
}

View File

@ -173,4 +173,21 @@ class CryptGpgExtended extends Crypt_GPG
return $armored;
}
/**
* @param mixed $data
* @param bool $isFile
* @param bool $allowEmpty
* @return resource|string|null
* @throws Crypt_GPG_FileException
* @throws Crypt_GPG_NoDataException
*/
protected function _prepareInput($data, $isFile = false, $allowEmpty = true)
{
if ($isFile && $data instanceof TmpFileTool) {
return $data->resource();
}
return parent::_prepareInput($data, $isFile, $allowEmpty);
}
}

View File

@ -1,6 +1,9 @@
<?php
class GpgTool
{
/** @var CryptGpgExtended */
private $gpg;
/**
* @return CryptGpgExtended
* @throws Exception
@ -22,19 +25,16 @@ class GpgTool
throw new Exception("Configuration option 'GnuPG.homedir' is not set, Crypt_GPG cannot be initialized.");
}
$options = array(
$options = [
'homedir' => $homedir,
'gpgconf' => Configure::read('GnuPG.gpgconf'),
'binary' => Configure::read('GnuPG.binary') ?: '/usr/bin/gpg',
);
];
return new CryptGpgExtended($options);
}
/** @var CryptGpgExtended */
private $gpg;
public function __construct($gpg)
public function __construct(CryptGpgExtended $gpg = null)
{
$this->gpg = $gpg;
}
@ -47,11 +47,13 @@ class GpgTool
public function searchGpgKey($search)
{
$uri = 'https://openpgp.circl.lu/pks/lookup?search=' . urlencode($search) . '&op=index&fingerprint=on&options=mr';
$response = $this->keyServerLookup($uri);
if ($response->code == 404) {
return array(); // no keys found
} else if ($response->code != 200) {
throw new Exception("Fetching the '$uri' failed with HTTP error {$response->code}: {$response->reasonPhrase}");
try {
$response = $this->keyServerLookup($uri);
} catch (HttpSocketHttpException $e) {
if ($e->getCode() === 404) {
return [];
}
throw $e;
}
return $this->extractKeySearch($response->body);
}
@ -64,11 +66,13 @@ class GpgTool
public function fetchGpgKey($fingerprint)
{
$uri = 'https://openpgp.circl.lu/pks/lookup?search=0x' . urlencode($fingerprint) . '&op=get&options=mr';
$response = $this->keyServerLookup($uri);
if ($response->code == 404) {
return null; // key with given fingerprint not found
} else if ($response->code != 200) {
throw new Exception("Fetching the '$uri' failed with HTTP error {$response->code}: {$response->reasonPhrase}");
try {
$response = $this->keyServerLookup($uri);
} catch (HttpSocketHttpException $e) {
if ($e->getCode() === 404) {
return null;
}
throw $e;
}
$key = $response->body;
@ -169,30 +173,20 @@ class GpgTool
$advancedUrl = "https://openpgpkey.$domain/.well-known/openpgpkey/" . strtolower($domain) . "/hu/$localPartHash";
try {
$response = $this->keyServerLookup($advancedUrl);
return $this->processWkdResponse($response);
return $this->gpg->enarmor($response->body());
} catch (Exception $e) {
// pass, continue to direct method
}
$directUrl = "https://$domain/.well-known/openpgpkey/hu/$localPartHash";
$response = $this->keyServerLookup($directUrl);
return $this->processWkdResponse($response);
}
/**
* @param HttpSocketResponse $response
* @return string
* @throws Crypt_GPG_Exception
* @throws Crypt_GPG_InvalidOperationException
*/
private function processWkdResponse(HttpSocketResponse $response)
{
if ($response->code == 404) {
throw new NotFoundException("Key not found");
} else if (!$response->isOk()) {
throw new Exception("Fetching the WKD failed with HTTP error {$response->code}: {$response->reasonPhrase}");
try {
$response = $this->keyServerLookup($directUrl);
} catch (HttpSocketHttpException $e) {
if ($e->getCode() === 404) {
throw new NotFoundException("Key not found");
}
throw $e;
}
return $this->gpg->enarmor($response->body());
}
@ -232,17 +226,18 @@ class GpgTool
/**
* @param string $uri
* @return HttpSocketResponse
* @return HttpSocketResponseExtended
* @throws HttpSocketHttpException
* @throws Exception
*/
private function keyServerLookup($uri)
{
App::uses('SyncTool', 'Tools');
$syncTool = new SyncTool();
$HttpSocket = $syncTool->setupHttpSocket();
$HttpSocket = $syncTool->createHttpSocket(['compress' => true]);
$response = $HttpSocket->get($uri);
if ($response === false) {
throw new Exception("Could not fetch '$uri'.");
if (!$response->isOk()) {
throw new HttpSocketHttpException($response, $uri);
}
return $response;
}

View File

@ -93,7 +93,7 @@ class JSONConverterTool
if ($raw) {
return $result;
}
return json_encode($result, JSON_PRETTY_PRINT);
return json_encode($result, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
/**
@ -127,7 +127,7 @@ class JSONConverterTool
}
}
if (isset($event['errors'])) {
yield '},"errors":' . json_encode($event['errors']) . '}';
yield '},"errors":' . json_encode($event['errors'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . '}';
} else {
yield "}}";
}

View File

@ -26,7 +26,15 @@ class JsonTool
*/
public static function decode($value)
{
$flags = defined('JSON_THROW_ON_ERROR') ? JSON_THROW_ON_ERROR : 0; // Throw exception on error if supported
return json_decode($value, true, 512, $flags);
if (defined('JSON_THROW_ON_ERROR')) {
// JSON_THROW_ON_ERROR is supported since PHP 7.3
return json_decode($value, true, 512, JSON_THROW_ON_ERROR);
}
$decoded = json_decode($value, true);
if ($decoded === null) {
throw new UnexpectedValueException('Could not parse JSON: ' . json_last_error_msg(), json_last_error());
}
return $decoded;
}
}

View File

@ -19,7 +19,7 @@ class RandomTool
* @return string
* @throws Exception
*/
public function random_str($crypto_secure = true, $length = 32, $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
public static function random_str($crypto_secure = true, $length = 32, $charset = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ')
{
// Type checks:
if (!is_bool($crypto_secure)) {

View File

@ -71,14 +71,26 @@ class SendEmailTemplate
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'html';
try {
$html = $View->render($this->viewName);
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'html' . DS . 'Custom';
$html = $View->render($this->viewName); // Attempt to load a custom template if it exists
} catch (MissingViewException $e) {
$html = null; // HTMl template is optional
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'html';
try {
$html = $View->render($this->viewName);
} catch (MissingViewException $e) {
$html = null; // HTMl template is optional
}
}
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'text';
$View->hasRendered = false;
$text = $View->render($this->viewName);
try {
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'text' . DS . 'Custom';
$text = $View->render($this->viewName); // Attempt to load a custom template if it exists
} catch (MissingViewException $e) {
$View->viewPath = $View->layoutPath = 'Emails' . DS . 'text';
$text = $View->render($this->viewName);
}
// Template can change default subject.
if ($View->get('subject')) {

View File

@ -20,6 +20,9 @@ class ServerSyncTool
/** @var HttpSocketExtended */
private $socket;
/** @var CryptographicKey */
private $cryptographicKey;
/** @var array|null */
private $info;
@ -418,8 +421,10 @@ class ServerSyncTool
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);
if (!$this->cryptographicKey) {
$this->cryptographicKey = ClassRegistry::init('CryptographicKey');
}
$signature = $this->cryptographicKey->signWithInstanceKey($data);
if (empty($signature)) {
throw new Exception(__("Invalid signing key. This should never happen."));
}

View File

@ -1,14 +1,14 @@
<?php
class TmpFileTool
{
/** @var resource */
/** @var resource|null */
private $tmpfile;
/** @var string */
private $separator;
/**
* @param int $maxInMemory How many bytes should keep in memory before creating file on disk. By default is is 2 MB.
* @param int $maxInMemory How many bytes should keep in memory before creating file on disk. By default is is 5 MB.
* @throws Exception
*/
public function __construct($maxInMemory = null)
@ -88,7 +88,7 @@ class TmpFileTool
* @param string $delimiter
* @param string $enclosure
* @param string $escape
* @return Generator
* @return Generator<array>
* @throws Exception
*/
public function intoParsedCsv($delimiter = ',', $enclosure = '"', $escape = "\\")
@ -144,20 +144,17 @@ class TmpFileTool
}
/**
* @param boolean $close
* @return string
* @throws Exception
*/
public function intoString($close = true)
public function intoString()
{
$this->rewind();
$string = stream_get_contents($this->tmpfile);
if ($string === false) {
throw new Exception('Could not read from temporary file.');
}
if ($close) {
$this->close();
}
$this->close();
return $string;
}
@ -175,6 +172,16 @@ class TmpFileTool
$this->close();
}
/**
* @return resource
* @throws Exception
*/
public function resource()
{
$this->rewind();
return $this->tmpfile;
}
/**
* @return int
* @throws Exception

View File

@ -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
@ -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);
@ -2780,7 +2784,7 @@ class AppModel extends Model
* @return array[]
* @throws JsonException
*/
protected function setupSyncRequest(array $server, $model = 'Server')
public function setupSyncRequest(array $server, $model = 'Server')
{
$version = implode('.', $this->checkMISPVersion());
$commit = $this->checkMIPSCommit();
@ -3197,16 +3201,7 @@ class AppModel extends Model
*/
public function jsonDecode($json)
{
if (defined('JSON_THROW_ON_ERROR')) {
// JSON_THROW_ON_ERROR is supported since PHP 7.3
$decoded = json_decode($json, true, 512, JSON_THROW_ON_ERROR);
} else {
$decoded = json_decode($json, true);
if ($decoded === null) {
throw new UnexpectedValueException('Could not parse JSON: ' . json_last_error_msg(), json_last_error());
}
}
$decoded = JsonTool::decode($json);
if (!is_array($decoded)) {
throw new UnexpectedValueException('JSON must be array type, get ' . gettype($decoded));
}

View File

@ -1023,7 +1023,7 @@ class Attribute extends AppModel
'order' => false,
'limit' => 11,
'flatten' => 1,
'contain' => ['AttributeTag' => false],
'contain' => ['AttributeTag' => false, 'Object' => false],
);
$resultArray[$key]['related'] = $this->fetchAttributes($user, $options);
}
@ -3154,6 +3154,7 @@ class Attribute extends AppModel
}
$simple_params = array(
'Attribute' => array(
'sharinggroup' => array('function' => 'set_filter_sharing_group'),
'value' => array('function' => 'set_filter_value'),
'category' => array('function' => 'set_filter_simple_attribute'),
'type' => array('function' => 'set_filter_type'),
@ -3169,6 +3170,7 @@ class Attribute extends AppModel
'comment' => array('function' => 'set_filter_comment')
),
'Event' => array(
'sharinggroup' => array('function' => 'set_filter_sharing_group'),
'eventid' => array('function' => 'set_filter_eventid'),
'eventinfo' => array('function' => 'set_filter_eventinfo'),
'ignore' => array('function' => 'set_filter_ignore'),

View File

@ -272,7 +272,7 @@ class AuditLog extends AppModel
if ($title) {
$entry .= " -- $title";
}
$this->syslog->write('info', $entry);
$this->syslog->write(LOG_INFO, $entry);
}
return true;
}

View File

@ -1,8 +1,6 @@
<?php
App::uses('AppModel', 'Model');
App::uses('RandomTool', 'Tools');
App::uses('CidrTool', 'Tools');
App::uses('JsonTool', 'Tools');
App::uses('BlowfishConstantPasswordHasher', 'Controller/Component/Auth');
/**
@ -15,9 +13,10 @@ class AuthKey extends AppModel
public $actsAs = array(
'AuditLog',
'SysLogLogable.SysLogLogable' => array(
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'full'),
'userModel' => 'User',
'userKey' => 'user_id',
'change' => 'full'
),
'Containable',
);
@ -25,9 +24,20 @@ class AuthKey extends AppModel
'User'
);
public $authkey_raw = false;
public $validate = [
'uuid' => [
'rule' => 'uuid',
'message' => 'Please provide a valid RFC 4122 UUID',
],
'user_id' => [
'rule' => 'userExists',
'message' => 'User doesn\'t exists',
],
'read_only' => [
'rule' => 'boolean',
],
];
// massage the data before we send it off for validation before saving anything
public function beforeValidate($options = array())
{
if (empty($this->data['AuthKey']['id'])) {
@ -35,16 +45,14 @@ class AuthKey extends AppModel
$this->data['AuthKey']['uuid'] = CakeText::uuid();
}
if (empty($this->data['AuthKey']['authkey'])) {
$authkey = (new RandomTool())->random_str(true, 40);
$authkey = RandomTool::random_str(true, 40);
} else {
$authkey = $this->data['AuthKey']['authkey'];
}
$passwordHasher = $this->getHasher();
$this->data['AuthKey']['authkey'] = $passwordHasher->hash($authkey);
$this->data['AuthKey']['authkey'] = $this->getHasher()->hash($authkey);
$this->data['AuthKey']['authkey_start'] = substr($authkey, 0, 4);
$this->data['AuthKey']['authkey_end'] = substr($authkey, -4);
$this->data['AuthKey']['authkey_raw'] = $authkey;
$this->authkey_raw = $authkey;
}
if (!empty($this->data['AuthKey']['allowed_ips'])) {
@ -54,6 +62,7 @@ class AuthKey extends AppModel
if (empty($allowedIps)) {
$allowedIps = [];
} else {
// Split by new line char or by comma
$allowedIps = preg_split('/([\n,])/', $allowedIps);
$allowedIps = array_map('trim', $allowedIps);
}
@ -336,6 +345,16 @@ class AuthKey extends AppModel
$this->User->updateAll(['date_modified' => time()], ['User.id' => $userId]);
}
/**
* Validation
* @param array $check
* @return bool
*/
public function userExists(array $check)
{
return $this->User->hasAny(['id' => $check['user_id']]);
}
/**
* @return AbstractPasswordHasher
*/

View File

@ -35,6 +35,9 @@ class CryptographicKey extends AppModel
public $validate = [];
/** @var CryptGpgExtended|null */
private $gpg;
public function __construct($id = false, $table = null, $ds = null)
{
parent::__construct($id, $table, $ds);
@ -44,6 +47,12 @@ class CryptographicKey extends AppModel
$this->gpg = null;
}
$this->validate = [
'uuid' => [
'uuid' => [
'rule' => 'uuid',
'message' => 'Please provide a valid RFC 4122 UUID',
],
],
'type' => [
'rule' => ['inList', $this->validTypes],
'message' => __('Invalid key type'),
@ -76,16 +85,32 @@ class CryptographicKey extends AppModel
$this->data['CryptographicKey']['uuid'] = CakeText::uuid();
$this->data['CryptographicKey']['fingerprint'] = $this->extractKeyData($this->data['CryptographicKey']['type'], $this->data['CryptographicKey']['key_data']);
}
$existingKeyForObject = $this->find('first', [
'recursive'
]);
return true;
}
/**
* @return string Instance key fingerprint
* @throws Crypt_GPG_BadPassphraseException
* @throws Crypt_GPG_Exception
*/
public function ingestInstanceKey()
{
// If instance just key stored just in GPG homedir, use that key.
if (Configure::read('MISP.download_gpg_from_homedir')) {
if (!$this->gpg) {
throw new Exception("Could not initiate GPG");
}
/** @var Crypt_GPG_Key[] $keys */
$keys = $this->gpg->getKeys(Configure::read('GnuPG.email'));
if (empty($keys)) {
return false;
}
$this->gpg->addSignKey($keys[0], Configure::read('GnuPG.password'));
return $keys[0]->getPrimaryKey()->getFingerprint();
}
try {
$redis = $this->setupRedis();
$redis = $this->setupRedisWithException();
} catch (Exception $e) {
$redis = false;
}
@ -123,25 +148,29 @@ class CryptographicKey extends AppModel
return $fingerprint;
}
/**
* @param string $data
* @return false|string
* @throws Crypt_GPG_BadPassphraseException
* @throws Crypt_GPG_Exception
* @throws Crypt_GPG_KeyNotFoundException
*/
public function signWithInstanceKey($data)
{
if (!$this->ingestInstanceKey()) {
return false;
}
$data = preg_replace("/\s+/", "", $data);
$signature = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_DETACHED);
return $signature;
}
public function signFileWithInstanceKey($path)
{
if (!$this->ingestInstanceKey()) {
return false;
}
$signature = $this->gpg->signFile($path, Crypt_GPG::SIGN_MODE_DETACHED);
$signature = $this->gpg->sign($data, Crypt_GPG::SIGN_MODE_DETACHED, Crypt_GPG::ARMOR_BINARY);
return $signature;
}
/**
* @param string $data
* @param string $signature
* @param string $key
* @return bool
*/
public function verifySignature($data, $signature, $key)
{
$this->error = false;
@ -217,20 +246,15 @@ class CryptographicKey extends AppModel
public function uniqueKeyForElement($data)
{
$existingKey = $this->find('first', [
'recursive' => -1,
'conditions' => [
'parent_type' => $this->data['CryptographicKey']['parent_type'],
'parent_id' => $this->data['CryptographicKey']['parent_id'],
'key_data' => $this->data['CryptographicKey']['key_data'],
'type' => $this->data['CryptographicKey']['type']
],
'fields' => ['id']
return !$this->hasAny([
'parent_type' => $this->data['CryptographicKey']['parent_type'],
'parent_id' => $this->data['CryptographicKey']['parent_id'],
'key_data' => $this->data['CryptographicKey']['key_data'],
'type' => $this->data['CryptographicKey']['type'],
]);
return empty($existingKey);
}
public function validateProtectedEvent($raw_data, $user, $pgp_signature, $event)
public function validateProtectedEvent($raw_data, array $user, $pgp_signature, array $event)
{
$eventCryptoGraphicKey = [];
if (!empty($event['Event']['CryptographicKey'])) { // Depending if $event comes from fetchEvent or from pushed data
@ -240,8 +264,7 @@ class CryptographicKey extends AppModel
}
if (empty($eventCryptoGraphicKey)) {
$message = __('No valid signatures found for validating the signature.');
$this->Log = ClassRegistry::init('Log');
$this->Log->createLogEntry($user, 'validateSig', 'Event', $event['Event']['id'], $message);
$this->loadLog()->createLogEntry($user, 'validateSig', 'Event', $event['Event']['id'], $message);
return false;
}
foreach ($eventCryptoGraphicKey as $supplied_key) {
@ -249,19 +272,26 @@ class CryptographicKey extends AppModel
return true;
}
}
$this->Log = ClassRegistry::init('Log');
$message = __('Could not validate the signature.');
$this->Log->createLogEntry($user, 'validateSig', 'Event', $event['Event']['id'], $message);
$this->loadLog()->createLogEntry($user, 'validateSig', 'Event', $event['Event']['id'], $message);
return false;
}
public function captureCryptographicKeyUpdate($user, $cryptographicKeys, $parent_id, $type)
/**
* @param array $user
* @param array $cryptographicKeys
* @param int $parent_id
* @param string $type
* @return void
* @throws Exception
*/
public function captureCryptographicKeyUpdate(array $user, array $cryptographicKeys, $parent_id, $type)
{
$existingKeys = $this->find('first', [
'recursive' => -1,
'conditions' => [
'parent_type' => $type,
'parent_id' => $parent_id
'parent_id' => $parent_id,
],
'fields' => [
'id',
@ -269,15 +299,14 @@ class CryptographicKey extends AppModel
'parent_type',
'parent_id',
'revoked',
'fingerprint'
'fingerprint',
]
]);
$toRemove = [];
$results = ['add' => [], 'remove' => []];
foreach ($existingKeys as $k => $existingKey) {
foreach ($existingKeys as $existingKey) {
foreach ($cryptographicKeys as $k2 => $cryptographicKey) {
if ($existingKey['fingerprint'] === $cryptographicKey['fingerprint']) {
$found = true;
if ($cryptographicKey['revoked'] && !$existingKey['CryptographicKey']['revoked']) {
$existingKey['CryptographicKey']['revoked'] = 1;
$this->save($existingKey['CryptographicKey']);
@ -314,7 +343,6 @@ class CryptographicKey extends AppModel
$parent_id
);
$this->deleteAll(['CryptographicKey.id' => $toRemove]);
$this->Log = ClassRegistry::init('Log');
$this->Log->createLogEntry($user, 'updateCryptoKeys', $cryptographicKey['parent_type'], $cryptographicKey['parent_id'], $message);
$this->loadLog()->createLogEntry($user, 'updateCryptoKeys', $cryptographicKey['parent_type'], $cryptographicKey['parent_id'], $message);
}
}

View File

@ -94,8 +94,6 @@ class Event extends AppModel
public $shortDist = array(0 => 'Organisation', 1 => 'Community', 2 => 'Connected', 3 => 'All', 4 => ' sharing Group');
public $export_types = [];
public $validFormats = array(
'attack' => array('html', 'AttackExport', 'html'),
'attack-sightings' => array('json', 'AttackSightingsExport', 'json'),
@ -301,118 +299,6 @@ class Event extends AppModel
]
);
public function __construct($id = false, $table = null, $ds = null)
{
parent::__construct($id, $table, $ds);
$this->export_types = array(
'json' => array(
'extension' => '.json',
'type' => 'JSON',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'json'),
'description' => __('Click this to download all events and attributes that you have access to in MISP JSON format.'),
),
'xml' => array(
'extension' => '.xml',
'type' => 'XML',
'scope' => 'Event',
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'xml'),
'requiresPublished' => 0,
'description' => __('Click this to download all events and attributes that you have access to in MISP XML format.'),
),
'csv_sig' => array(
'extension' => '.csv',
'type' => 'CSV_Sig',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('published' => 1, 'to_ids' => 1, 'returnFormat' => 'csv'),
'description' => __('Click this to download all attributes that are indicators and that you have access to (except file attachments) in CSV format.'),
),
'csv_all' => array(
'extension' => '.csv',
'type' => 'CSV_All',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('ignore' => 1, 'returnFormat' => 'csv'),
'description' => __('Click this to download all attributes that you have access to (except file attachments) in CSV format.'),
),
'suricata' => array(
'extension' => '.rules',
'type' => 'Suricata',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'suricata'),
'description' => __('Click this to download all network related attributes that you have access to under the Suricata rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'snort' => array(
'extension' => '.rules',
'type' => 'Snort',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'snort'),
'description' => __('Click this to download all network related attributes that you have access to under the Snort rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'bro' => array(
'extension' => '.intel',
'type' => 'Bro',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'bro'),
'description' => __('Click this to download all network related attributes that you have access to under the Bro rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'stix' => array(
'extension' => '.xml',
'type' => 'STIX',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1),
'description' => __('Click this to download a STIX document containing the STIX version of all events and attributes that you have access to.')
),
'stix2' => array(
'extension' => '.json',
'type' => 'STIX2',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix2', 'includeAttachments' => 1),
'description' => __('Click this to download a STIX2 document containing the STIX2 version of all events and attributes that you have access to.')
),
'rpz' => array(
'extension' => '.txt',
'type' => 'RPZ',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'rpz'),
'description' => __('Click this to download an RPZ Zone file generated from all ip-src/ip-dst, hostname, domain attributes. This can be useful for DNS level firewalling. Only published events and attributes marked as IDS Signature are exported.')
),
'text' => array(
'extension' => '.txt',
'type' => 'TEXT',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'text', 'includeAttachments' => 1),
'description' => __('Click on one of the buttons below to download all the attributes with the matching type. This list can be used to feed forensic software when searching for susipicious files. Only published events and attributes marked as IDS Signature are exported.')
),
'yara' => array(
'extension' => '.yara',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara'),
'description' => __('Click this to download Yara rules generated from all relevant attributes.')
),
'yara-json' => array(
'extension' => '.json',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara-json'),
'description' => __('Click this to download Yara rules generated from all relevant attributes. Rules are returned in a JSON format with information about origin (generated or parsed) and validity.')
),
);
}
private $assetCache = [];
public function beforeDelete($cascade = true)
@ -2667,6 +2553,19 @@ class Event extends AppModel
return $container;
}
public function set_filter_sharing_group(&$params, $conditions, $options)
{
if (!empty($params['sharinggroup'])) {
$params['sharinggroup'] = $this->convert_filters($params['sharinggroup']);
if ($options['scope'] === 'Attribute') {
$conditions = $this->generic_add_filter($conditions, $params['sharinggroup'], ['Event.sharing_group_id', 'Attribute.sharing_group_id']);
} else {
$conditions = $this->generic_add_filter($conditions, $params['sharinggroup'], 'Event.sharing_group_id');
}
}
return $conditions;
}
public function set_filter_org(&$params, $conditions, $options)
{
if (!empty($params['org'])) {
@ -5581,7 +5480,7 @@ class Event extends AppModel
}
$this->Warninglist = ClassRegistry::init('Warninglist');
$complexTypeTool->setTLDs($this->Warninglist->fetchTLDLists());
$freetextResults = array_merge($freetextResults, $complexTypeTool->checkComplexRouter($value, 'FreeText'));
$freetextResults = array_merge($freetextResults, $complexTypeTool->checkFreeText($value));
if (!empty($freetextResults)) {
foreach ($freetextResults as &$ft) {
$temp = array();
@ -6772,7 +6671,7 @@ class Event extends AppModel
return $attribute_save;
}
public function processFreeTextDataRouter($user, $attributes, $id, $default_comment = '', $proposals = false, $adhereToWarninglists = false, $returnRawResults = false)
public function processFreeTextDataRouter(array $user, array $attributes, $id, $default_comment = '', $proposals = false, $adhereToWarninglists = false, $returnRawResults = false)
{
if (Configure::read('MISP.background_jobs') && count($attributes) > 5) { // on background process just big attributes batch
/** @var Job $job */
@ -7588,4 +7487,118 @@ class Event extends AppModel
$banStatus['message'] = __('Emailing republishing ban setting is not enabled');
return $banStatus;
}
/**
* @return array[]
* @deprecated
*/
public function exportTypes()
{
return array(
'json' => array(
'extension' => '.json',
'type' => 'JSON',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'json'),
'description' => __('Click this to download all events and attributes that you have access to in MISP JSON format.'),
),
'xml' => array(
'extension' => '.xml',
'type' => 'XML',
'scope' => 'Event',
'params' => array('includeAttachments' => 1, 'ignore' => 1, 'returnFormat' => 'xml'),
'requiresPublished' => 0,
'description' => __('Click this to download all events and attributes that you have access to in MISP XML format.'),
),
'csv_sig' => array(
'extension' => '.csv',
'type' => 'CSV_Sig',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('published' => 1, 'to_ids' => 1, 'returnFormat' => 'csv'),
'description' => __('Click this to download all attributes that are indicators and that you have access to (except file attachments) in CSV format.'),
),
'csv_all' => array(
'extension' => '.csv',
'type' => 'CSV_All',
'scope' => 'Event',
'requiresPublished' => 0,
'params' => array('ignore' => 1, 'returnFormat' => 'csv'),
'description' => __('Click this to download all attributes that you have access to (except file attachments) in CSV format.'),
),
'suricata' => array(
'extension' => '.rules',
'type' => 'Suricata',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'suricata'),
'description' => __('Click this to download all network related attributes that you have access to under the Suricata rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'snort' => array(
'extension' => '.rules',
'type' => 'Snort',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'snort'),
'description' => __('Click this to download all network related attributes that you have access to under the Snort rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'bro' => array(
'extension' => '.intel',
'type' => 'Bro',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'bro'),
'description' => __('Click this to download all network related attributes that you have access to under the Bro rule format. Only published events and attributes marked as IDS Signature are exported. Administration is able to maintain a allowedlist containing host, domain name and IP numbers to exclude from the NIDS export.'),
),
'stix' => array(
'extension' => '.xml',
'type' => 'STIX',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1),
'description' => __('Click this to download a STIX document containing the STIX version of all events and attributes that you have access to.')
),
'stix2' => array(
'extension' => '.json',
'type' => 'STIX2',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix2', 'includeAttachments' => 1),
'description' => __('Click this to download a STIX2 document containing the STIX2 version of all events and attributes that you have access to.')
),
'rpz' => array(
'extension' => '.txt',
'type' => 'RPZ',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'rpz'),
'description' => __('Click this to download an RPZ Zone file generated from all ip-src/ip-dst, hostname, domain attributes. This can be useful for DNS level firewalling. Only published events and attributes marked as IDS Signature are exported.')
),
'text' => array(
'extension' => '.txt',
'type' => 'TEXT',
'scope' => 'Attribute',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'text', 'includeAttachments' => 1),
'description' => __('Click on one of the buttons below to download all the attributes with the matching type. This list can be used to feed forensic software when searching for susipicious files. Only published events and attributes marked as IDS Signature are exported.')
),
'yara' => array(
'extension' => '.yara',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara'),
'description' => __('Click this to download Yara rules generated from all relevant attributes.')
),
'yara-json' => array(
'extension' => '.json',
'type' => 'Yara',
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'yara-json'),
'description' => __('Click this to download Yara rules generated from all relevant attributes. Rules are returned in a JSON format with information about origin (generated or parsed) and validity.')
),
);
}
}

View File

@ -74,6 +74,11 @@ class Feed extends AppModel
'url_params' => ''
];
const SUPPORTED_URL_PARAM_FILTERS = [
'timestamp',
'publish_timestamp',
];
const CACHE_DIR = APP . 'tmp' . DS . 'cache' . DS . 'feeds' . DS;
/*
@ -126,12 +131,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.';
}
}
@ -776,6 +782,10 @@ class Feed extends AppModel
}
}
}
$url_params = !empty($filterRules['url_params']) ? $filterRules['url_params'] : [];
if (!$this->passesURLParamFilters($url_params, $event['Event'])) {
return false;
}
return true;
}
@ -813,7 +823,7 @@ class Feed extends AppModel
}
}
if (!$found) {
unset($k);
unset($events[$k]);
continue;
}
}
@ -828,14 +838,48 @@ class Feed extends AppModel
}
}
if ($found) {
unset($k);
unset($events[$k]);
}
}
}
$url_params = !empty($filterRules['url_params']) ? $filterRules['url_params'] : [];
if (!$this->passesURLParamFilters($url_params, $event)) {
unset($events[$k]);
}
}
return $events;
}
private function passesURLParamFilters($url_params, $event): bool
{
$this->Attribute = ClassRegistry::init('Attribute');
if (!empty($url_params['timestamp'])) {
$timestamps = $this->Attribute->setTimestampConditions($url_params['timestamp'], [], '', true);
if (is_array($timestamps)) {
if ($event['timestamp'] < $timestamps[0] || $event['timestamp'] > $timestamps[1]) {
return false;
}
} else {
if ($event['timestamp'] < $timestamps) {
return false;
}
}
}
if (!empty($url_params['publish_timestamp'])) {
$timestamps = $this->Attribute->setTimestampConditions($url_params['publish_timestamp'], [], '', true);
if (is_array($timestamps)) {
if ($event['timestamp'] < $timestamps[0] || $event['timestamp'] > $timestamps[1]) {
return false;
}
} else {
if ($event['timestamp'] < $timestamps) {
return false;
}
}
}
return true;
}
/**
* @param array $feed
* @param string $uuid
@ -997,6 +1041,7 @@ class Feed extends AppModel
if ($filterRules === null) {
throw new Exception('Could not parse feed filter rules JSON: ' . json_last_error_msg(), json_last_error());
}
$filterRules['url_params'] = !empty($filterRules['url_params']) ? $this->jsonDecode($filterRules['url_params']) : [];
}
return $filterRules;
}
@ -1929,6 +1974,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 {

View File

@ -101,6 +101,11 @@ class Galaxy extends AppModel
];
}
/**
* @param array $galaxies
* @param array $cluster_package
* @return array
*/
private function __getPreExistingClusters(array $galaxies, array $cluster_package)
{
$temp = $this->GalaxyCluster->find('all', array(
@ -110,11 +115,7 @@ class Galaxy extends AppModel
'recursive' => -1,
'fields' => array('version', 'id', 'value', 'uuid')
));
$existingClusters = [];
foreach ($temp as $v) {
$existingClusters[$v['GalaxyCluster']['value']] = $v;
}
return $existingClusters;
return array_column(array_column($temp, 'GalaxyCluster'), null, 'value');
}
private function __deleteOutdated(bool $force, array $cluster_package, array $existingClusters)
@ -132,19 +133,20 @@ class Galaxy extends AppModel
} else {
$cluster_package['values'][$k]['version'] = 0;
}
if (!empty($existingClusters[$cluster['value']])) {
if ($force || $existingClusters[$cluster['value']]['GalaxyCluster']['version'] < $cluster_package['values'][$k]['version']) {
$cluster_ids_to_delete[] = $existingClusters[$cluster['value']]['GalaxyCluster']['id'];
$cluster_uuids_to_delete[] = $existingClusters[$cluster['value']]['GalaxyCluster']['uuid'];
if (isset($existingClusters[$cluster['value']])) {
$existing = $existingClusters[$cluster['value']];
if ($force || $existing['version'] < $cluster_package['values'][$k]['version']) {
$cluster_ids_to_delete[] = $existing['id'];
$cluster_uuids_to_delete[] = $existing['uuid'];
} else {
unset($cluster_package['values'][$k]);
}
}
}
if (!empty($cluster_ids_to_delete)) {
$this->GalaxyCluster->GalaxyElement->deleteAll(array('GalaxyElement.galaxy_cluster_id' => $cluster_ids_to_delete), false, false);
$this->GalaxyCluster->GalaxyClusterRelation->deleteRelations(array('GalaxyClusterRelation.galaxy_cluster_uuid' => $cluster_uuids_to_delete));
$this->GalaxyCluster->deleteAll(array('GalaxyCluster.id' => $cluster_ids_to_delete), false, false);
$this->GalaxyCluster->GalaxyElement->deleteAll(array('GalaxyElement.galaxy_cluster_id' => $cluster_ids_to_delete), false);
$this->GalaxyCluster->GalaxyClusterRelation->deleteAll(array('GalaxyClusterRelation.galaxy_cluster_uuid' => $cluster_uuids_to_delete));
$this->GalaxyCluster->deleteAll(array('GalaxyCluster.id' => $cluster_ids_to_delete), false);
}
return $cluster_package;
}

View File

@ -5,6 +5,7 @@ App::uses('TmpFileTool', 'Tools');
/**
* @property Tag $Tag
* @property GalaxyClusterRelation $GalaxyClusterRelation
* @property GalaxyElement $GalaxyElement
*/
class GalaxyCluster extends AppModel
{
@ -108,10 +109,10 @@ class GalaxyCluster extends AppModel
if (!isset($cluster['published'])) {
$cluster['published'] = false;
}
if (!isset($cluster['authors']) || $cluster['authors'] === null) {
if (!isset($cluster['authors'])) {
$cluster['authors'] = '';
} elseif (is_array($cluster['authors'])) {
$cluster['authors'] = json_encode($cluster['authors']);
$cluster['authors'] = JsonTool::encode($cluster['authors']);
}
return true;
}
@ -120,24 +121,24 @@ class GalaxyCluster extends AppModel
{
foreach ($results as $k => $result) {
if (isset($result[$this->alias]['authors'])) {
$results[$k][$this->alias]['authors'] = json_decode($results[$k][$this->alias]['authors'], true);
$results[$k][$this->alias]['authors'] = json_decode($result[$this->alias]['authors'], true);
}
if (isset($result[$this->alias]['distribution']) && $results[$k][$this->alias]['distribution'] != 4) {
if (isset($result[$this->alias]['distribution']) && $result[$this->alias]['distribution'] != 4) {
unset($results[$k]['SharingGroup']);
}
if (isset($result[$this->alias]['org_id']) && $results[$k][$this->alias]['org_id'] == 0) {
if (isset($result[$this->alias]['org_id']) && $result[$this->alias]['org_id'] == 0) {
if (isset($results[$k]['Org'])) {
$results[$k]['Org'] = Organisation::GENERIC_MISP_ORGANISATION;
}
}
if (isset($result[$this->alias]['orgc_id']) && $results[$k][$this->alias]['orgc_id'] == 0) {
if (isset($result[$this->alias]['orgc_id']) && $result[$this->alias]['orgc_id'] == 0) {
if (isset($results[$k]['Orgc'])) {
$results[$k]['Orgc'] = Organisation::GENERIC_MISP_ORGANISATION;
}
}
if (!empty($result['GalaxyClusterRelation'])) {
foreach ($results[$k]['GalaxyClusterRelation'] as $i => $relation) {
foreach ($result['GalaxyClusterRelation'] as $i => $relation) {
if (isset($relation['distribution']) && $relation['distribution'] != 4) {
unset($results[$k]['GalaxyClusterRelation'][$i]['SharingGroup']);
}

View File

@ -157,11 +157,6 @@ class GalaxyClusterRelation extends AppModel
return array_unique(array_merge($existingRelationships, $objectRelationships));
}
public function deleteRelations($conditions)
{
$this->deleteAll($conditions, false, false);
}
/**
* saveRelations
*

View File

@ -43,7 +43,7 @@ class Job extends AppModel
$this->Event = ClassRegistry::init('Event');
if (in_array($type, array_keys($this->Event->export_types)) && $type !== 'bro') {
if (in_array($type, array_keys($this->Event->exportTypes())) && $type !== 'bro') {
$this->getBackgroundJobsTool()->enqueue(
BackgroundJobsTool::CACHE_QUEUE,

View File

@ -204,7 +204,7 @@ class Log extends AppModel
*/
public function createLogEntry($user, $action, $model, $modelId = 0, $title = '', $change = '')
{
if (in_array($action, ['tag', 'galaxy', 'publish', 'publish_sightings'], true) && Configure::read('MISP.log_new_audit')) {
if (in_array($action, ['tag', 'galaxy', 'publish', 'publish_sightings', 'enable'], true) && Configure::read('MISP.log_new_audit')) {
return; // Do not store tag changes when new audit is enabled
}
if ($user === 'SYSTEM') {
@ -383,13 +383,13 @@ class Log extends AppModel
}
}
if ($this->syslog) {
$action = 'info';
$action = LOG_INFO;
if (isset($data['Log']['action'])) {
if (in_array($data['Log']['action'], self::ERROR_ACTIONS, true)) {
$action = 'err';
$action = LOG_ERR;
}
if (in_array($data['Log']['action'], self::WARNING_ACTIONS, true)) {
$action = 'warning';
$action = LOG_WARNING;
}
}

View File

@ -4,19 +4,35 @@ App::uses('AppModel', 'Model');
class RestClientHistory extends AppModel
{
public $belongsTo = array(
'Org' => array(
'className' => 'Organisation',
'foreignKey' => 'org_id',
'order' => array(),
'fields' => array('id', 'name', 'uuid')
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'order' => array(),
'fields' => array('id', 'email')
),
);
'Org' => array(
'className' => 'Organisation',
'foreignKey' => 'org_id',
'order' => array(),
'fields' => array('id', 'name', 'uuid')
),
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'order' => array(),
'fields' => array('id', 'email')
),
);
/**
* @param array $user
* @param array $history
* @return void
* @throws Exception
*/
public function insert(array $user, array $history)
{
$history['org_id'] = $user['org_id'];
$history['user_id'] = $user['id'];
$this->create();
$this->save($history, ['atomic' => false]);
$this->cleanup($user['id']);
}
public function cleanup($user_id)
{
@ -35,6 +51,6 @@ class RestClientHistory extends AppModel
'NOT' => array(
'RestClientHistory.id' => $keepIds
)
));
), false);
}
}

View File

@ -1980,7 +1980,7 @@ class Server extends AppModel
App::uses('Folder', 'Utility');
App::uses('File', 'Utility');
// delete all cache files
foreach ($this->Event->export_types as $type => $settings) {
foreach ($this->Event->exportTypes() as $type => $settings) {
$dir = new Folder(APP . 'tmp/cached_exports/' . $type);
// No caches created for this type of export, move on
if ($dir == null) {
@ -4614,6 +4614,28 @@ class Server extends AppModel
return $this->saveMany($toSave, ['validate' => false, 'fields' => ['authkey']]);
}
/**
* Return all Attribute and Object types
*/
public function getAllTypes(): array
{
$allTypes = [];
$this->Attribute = ClassRegistry::init('Attribute');
$this->ObjectTemplate = ClassRegistry::init('ObjectTemplate');
$objects = $this->ObjectTemplate->find('all', [
'recursive' => -1,
'fields' => ['uuid', 'name'],
'group' => ['uuid', 'name'],
]);
$allTypes = [
'attribute' => array_unique(Hash::extract(Hash::extract($this->Attribute->categoryDefinitions, '{s}.types'), '{n}.{n}')),
'object' => Hash::map($objects, '{n}.ObjectTemplate', function ($item) {
return ['id' => $item['uuid'], 'name' => sprintf('%s (%s)', $item['name'], $item['uuid'])];
})
];
return $allTypes;
}
/**
* Invalidate config.php from php opcode cache
*/
@ -5666,6 +5688,15 @@ class Server extends AppModel
'type' => 'boolean',
'null' => true,
],
'download_gpg_from_homedir' => [
'level' => self::SETTING_OPTIONAL,
'description' => __('Fetch GPG instance key from GPG homedir.'),
'value' => false,
'test' => 'testBool',
'type' => 'boolean',
'null' => true,
'cli_only' => true,
],
),
'GnuPG' => array(
'branch' => 1,

View File

@ -4,6 +4,7 @@ App::uses('AuthComponent', 'Controller/Component');
App::uses('RandomTool', 'Tools');
App::uses('GpgTool', 'Tools');
App::uses('SendEmail', 'Tools');
App::uses('SendEmailTemplate', 'Tools');
App::uses('BlowfishConstantPasswordHasher', 'Controller/Component/Auth');
/**
@ -832,6 +833,7 @@ class User extends AppModel
$gpg = $this->initializeGpg();
$sendEmail = new SendEmail($gpg);
$result = $sendEmail->sendToUser($user, $subject, $body, $bodyNoEnc,$replyToUser ?: []);
try {
$result = $sendEmail->sendToUser($user, $subject, $body, $bodyNoEnc,$replyToUser ?: []);
@ -867,16 +869,6 @@ class User extends AppModel
return true;
}
public function adminMessageResolve($message)
{
$resolveVars = array('$contact' => 'MISP.contact', '$org' => 'MISP.org', '$misp' => 'MISP.baseurl');
foreach ($resolveVars as $k => $v) {
$v = Configure::read($v);
$message = str_replace($k, $v, $message);
}
return $message;
}
/**
* @param string $email
* @return array
@ -955,24 +947,15 @@ class User extends AppModel
public function initiatePasswordReset($user, $firstTime = false, $simpleReturn = false, $fixedPassword = false)
{
$org = Configure::read('MISP.org');
$options = array('newUserText', 'passwordResetText');
$subjects = array('[' . $org . ' MISP] New user registration', '[' . $org . ' MISP] Password reset');
$textToFetch = $options[($firstTime ? 0 : 1)];
$subject = $subjects[($firstTime ? 0 : 1)];
$this->Server = ClassRegistry::init('Server');
$body = Configure::read('MISP.' . $textToFetch);
if (!$body) {
$body = $this->Server->serverSettings['MISP'][$textToFetch]['value'];
}
$body = $this->adminMessageResolve($body);
if ($fixedPassword) {
$password = $fixedPassword;
} else {
$password = $this->generateRandomPassword();
}
$body = str_replace('$password', $password, $body);
$body = str_replace('$username', $user['User']['email'], $body);
$body = str_replace('\n', PHP_EOL, $body);
$body = $this->preparePasswordResetEmail($user, $password, $firstTime, $subject);
$result = $this->sendEmail($user, $body, false, $subject);
if ($result) {
$this->id = $user['User']['id'];
@ -991,6 +974,22 @@ class User extends AppModel
}
}
private function preparePasswordResetEmail($user, $password, $firstTime, $subject)
{
$textToFetch = $firstTime ? 'newUserText': 'passwordResetText';
$this->Server = ClassRegistry::init('Server');
$bodyTemplate = Configure::read('MISP.' . $textToFetch);
if (!$bodyTemplate) {
$bodyTemplate = $this->Server->serverSettings['MISP'][$textToFetch]['value'];
}
$template = new SendEmailTemplate('password_reset');
$template->set('body', $bodyTemplate);
$template->set('user', $user);
$template->set('password', $password);
$template->subject($subject);
return $template;
}
public function getOrgAdminsForOrg($org_id, $excludeUserId = false)
{
$adminRoles = $this->Role->find('column', array(
@ -1223,13 +1222,12 @@ class User extends AppModel
}
// query
$this->Log = ClassRegistry::init('Log');
$result = $this->Log->createLogEntry($user, $action, $model, $modelId, $description, $fieldsResult);
$result = $this->loadLog()->createLogEntry($user, $action, $model, $modelId, $description, $fieldsResult);
// write to syslogd as well
App::import('Lib', 'SysLog.SysLog');
$syslog = new SysLog();
$syslog->write('notice', "$description -- $action" . (empty($fieldsResult) ? '' : ' -- ' . $result['Log']['change']));
$syslog->write(LOG_NOTICE, "$description -- $action" . (empty($fieldsResult) ? '' : ' -- ' . $result['Log']['change']));
}
/**

View File

@ -383,7 +383,7 @@ class Warninglist extends AppModel
$keys = array_keys($list['list']);
if ($keys === array_keys($keys)) {
foreach (array_chunk($list['list'], 500) as $chunk) {
foreach (array_chunk($list['list'], 1000) as $chunk) {
$valuesToInsert = [];
foreach ($chunk as $value) {
if (!empty($value)) {
@ -393,7 +393,7 @@ class Warninglist extends AppModel
$result = $db->insertMulti('warninglist_entries', ['value', 'warninglist_id'], $valuesToInsert);
}
} else { // import warninglist with comments
foreach (array_chunk($list['list'], 500, true) as $chunk) {
foreach (array_chunk($list['list'], 1000, true) as $chunk) {
$valuesToInsert = [];
foreach ($chunk as $value => $comment) {
if (!empty($value)) {

View File

@ -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;
}
}

View File

@ -38,9 +38,9 @@ class SysLog
* @param array $options Options for the SysLog, see above.
* @return void
*/
public function __construct($options = array())
public function __construct($options = [])
{
$options += array('ident' => LOGS, 'facility' => LOG_LOCAL0, 'to_stderr' => true);
$options += ['ident' => LOGS, 'facility' => LOG_LOCAL0, 'to_stderr' => true];
$option = LOG_PID; // include PID with each message
if ($options['to_stderr']) {
$option |= LOG_PERROR; // print log message also to standard error
@ -51,7 +51,7 @@ class SysLog
/**
* Implements writing to the specified syslog
*
* @param string $type The type of log you are making.
* @param int $type The type of log you are making.
* @param string $message The message you want to log.
* @return boolean success of write.
*/
@ -60,14 +60,9 @@ class SysLog
if (!$this->_log) {
return false;
}
$debugTypes = array('notice', 'info', 'debug');
$priority = LOG_INFO;
if ($type == 'error' || $type == 'warning') {
$priority = LOG_ERR;
} else if (in_array($type, $debugTypes)) {
$priority = LOG_DEBUG;
if (!is_int($type)) {
throw new InvalidArgumentException("Invalid log type `$type`, must be one of LOG_* constant.");
}
$output = date('Y-m-d H:i:s') . ' ' . ucfirst($type) . ': ' . $message;
return syslog($priority, $output);
return syslog($type, $message);
}
}

View File

@ -0,0 +1,65 @@
<?php
require_once __DIR__ . '/../Lib/Tools/GpgTool.php';
require_once __DIR__ . '/../Lib/Tools/TmpFileTool.php';
require_once __DIR__ . '/../Lib/Tools/CryptGpgExtended.php';
use PHPUnit\Framework\TestCase;
class GpgToolTest extends TestCase
{
public function testInit(): void
{
$gpg = $this->init();
$this->assertInstanceOf('CryptGpgExtended', $gpg);
$this->assertIsString($gpg->getVersion());
}
public function testSignAndVerify()
{
$gpg = $this->init();
include __DIR__ . '/../Config/config.php';
$gpg->addSignKey($config['GnuPG']['email'], $config['GnuPG']['password']);
$testString = 'ahojSvete';
$signature = $gpg->sign($testString, Crypt_GPG::SIGN_MODE_DETACHED, Crypt_GPG::ARMOR_BINARY);
$this->assertIsString($signature);
$verified = $gpg->verify($testString, $signature);
$this->assertIsArray($verified);
$this->assertCount(1, $verified);
$this->assertTrue($verified[0]->isValid());
$signature = $gpg->sign($testString, Crypt_GPG::SIGN_MODE_DETACHED, Crypt_GPG::ARMOR_ASCII);
$this->assertIsString($signature);
$verified = $gpg->verify($testString, $signature);
$this->assertIsArray($verified);
$this->assertCount(1, $verified);
$this->assertTrue($verified[0]->isValid());
// Tmp file
$tmpFile = new TmpFileTool();
$tmpFile->write($testString);
$signature = $gpg->signFile($tmpFile, null, Crypt_GPG::SIGN_MODE_DETACHED, Crypt_GPG::ARMOR_BINARY);
$this->assertIsString($signature);
$verified = $gpg->verify($testString, $signature);
$this->assertIsArray($verified);
$this->assertCount(1, $verified);
$this->assertTrue($verified[0]->isValid());
}
private function init(): CryptGpgExtended
{
require_once 'Crypt/GPG.php';
include __DIR__ . '/../Config/config.php';
$options = [
'homedir' => $config['GnuPG']['homedir'],
'gpgconf' => $config['GnuPG']['gpgconf'] ?? null,
'binary' => $config['GnuPG']['binary'] ?? '/usr/bin/gpg',
];
return new CryptGpgExtended($options);
}
}

View File

@ -35,12 +35,28 @@ class JSONConverterToolTest extends TestCase
$this->check($event);
}
public function testCheckJsonIsValidUnicodeSlashes(): void
{
$attribute = ['id' => 1, 'event_id' => 2, 'type' => 'ip-src', 'value' => '1.1.1.1'];
$event = ['Event' => ['id' => 2, 'info' => 'Test event ěšřžýáí \/'], 'errors' => 'chyba ě+š'];
for ($i = 0; $i < 5; $i++) {
$event['Attribute'][] = $attribute;
}
$this->check($event);
}
private function check(array $event): void
{
$json = '';
foreach (JSONConverterTool::streamConvert($event) as $part) {
$json .= $part;
}
// Check if result is the same without spaces
$jsonStreamWithoutSpaces = preg_replace("/\s+/", "", $json);
$jsonNormalWithoutSpaces = preg_replace("/\s+/", "", JSONConverterTool::convert($event));
$this->assertEquals($jsonNormalWithoutSpaces, $jsonStreamWithoutSpaces);
if (defined('JSON_THROW_ON_ERROR')) {
json_decode($json, true, 512, JSON_THROW_ON_ERROR);
$this->assertTrue(true);

View File

@ -1,6 +1,6 @@
<div class="dashboard_element">
<h4 class="blue bold">API info</h4>
<?php
echo '<h4 class="blue bold">API info</h4>';
foreach ($api_info as $key => $value) {
if (!empty($value)) {
if (is_array($value)) {
@ -30,11 +30,11 @@
}
$temp[] = $fieldName . $infoHtml;
}
$value = implode('<br />', $temp);
$value = implode('<br>', $temp);
} else {
$value = h($value);
}
echo sprintf('<span class=blue>%s</span>:<br /><div style="padding-left:10px;">%s</div>', ucfirst(h($key)), $value);
echo sprintf('<span class=blue>%s</span>:<br><div style="padding-left:10px;">%s</div>', ucfirst(h($key)), $value);
}
}
?>

View File

@ -4,12 +4,12 @@
<span id="showQB" class="btn btn-primary useCursorPointer" style="margin: 5px;"><span class="fa fa-wrench"> Query Builder</span></span>
<?php
$options = '<option value="">None</option>';
foreach($allValidApisFormated as $scope => $actions) {
$options .= sprintf('<optgroup label="%s">', $scope);
foreach($actions as $action) {
$options .= sprintf('<option value="%s">%s</option>', $action['url'], $action['action']);
}
foreach ($allAccessibleApis as $scope => $actions) {
$options .= sprintf('<optgroup label="%s">', $scope);
foreach ($actions as $action => $url) {
$options .= sprintf('<option value="%s">%s</option>', $url, $action);
}
}
echo sprintf('<select id="TemplateSelect">%s</select>', $options);
?>
<div id="apiInfo" style="margin-top: 15px;"></div>
@ -63,7 +63,7 @@
'class' => 'input-xxlarge'
));
?>
<div class="input clear" style="width:100%;" />
<div class="input clear" style="width:100%;"></div>
<?php
if (!empty(Configure::read('Security.rest_client_enable_arbitrary_urls'))) {
echo $this->Form->input('use_full_path', array(
@ -77,7 +77,7 @@
'onChange' => 'toggleRestClientBookmark();'
));
?>
<div class="input clear" style="width:100%;" />
<div class="input clear" style="width:100%;"></div>
<div id="bookmark-name" style="display:none;">
<?php
echo $this->Form->input('name', array(
@ -86,7 +86,7 @@
));
?>
</div>
<div class="input clear" style="width:100%;" />
<div class="input clear" style="width:100%;"></div>
<?php
echo $this->Form->input('show_result', array(
'label' => __('Show result'),
@ -157,7 +157,7 @@
}
echo '</div>';
}
if (!empty($data['data'])): ?>
if (isset($data['data'])): ?>
<h3><?= __('Response') ?></h3>
<div><span class="bold"><?= __('Queried URL') ?></span>: <?= h($data['url']) ?></div>
<div><span class="bold"><?= __('Response code') ?></span>: <?= h($data['code']) ?></div>
@ -220,18 +220,6 @@
)
));
?>
<script type="text/javascript">
var allValidApis = <?= json_encode($allValidApis); ?>;
var fieldsConstraint = <?= json_encode($allValidApisFieldsContraint); ?>;
$(function() {
populate_rest_history('history');
populate_rest_history('bookmark');
toggleRestClientBookmark();
setupCodeMirror();
});
</script>
<style>
.CodeMirror-wrap {
border: 1px solid #cccccc;

View File

@ -1,12 +1,14 @@
<?php
if ($field === 'value') {
echo $this->element('Events/View/value_field', ['object' => $object['Attribute']]);
} elseif ($field === 'timestamp') {
echo $this->Time->date($value);
} else {
if ($value === 'No') {
echo '<input type="checkbox" disabled>';
} else if ($value === 'Yes') {
echo '<input type="checkbox" checked disabled>';
} else {
echo nl2br(h($value)) . '&nbsp;';
echo nl2br(h($value), false);
}
}

View File

@ -320,9 +320,6 @@ echo $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'event
$('.screenshot').click(function() {
screenshotPopup($(this).attr('src'), $(this).attr('title'));
});
$('.addGalaxy').click(function() {
addGalaxyListener(this);
});
$('.sightings_advanced_add').click(function() {
var selected = [];
var object_context = $(this).data('object-context');
@ -338,16 +335,6 @@ echo $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'event
url = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id + "/" + object_context;
genericPopup(url, '#popover_box');
});
$('.correlation-toggle').click(function() {
var attribute_id = $(this).data('attribute-id');
getPopup(attribute_id, 'attributes', 'toggleCorrelation', '', '#confirmation_box');
return false;
});
$('.toids-toggle').click(function() {
var attribute_id = $(this).data('attribute-id');
getPopup(attribute_id, 'attributes', 'toggleToIDS', '', '#confirmation_box');
return false;
});
popoverStartup();
$(document).on('click', function(e) {
//did not click a popover toggle or popover

View File

@ -5,10 +5,10 @@
<button class="btn btn-inverse toggle qet" id="galaxies_toggle" data-toggle-type="galaxies">
<span class="fas fa-minus" title="<?php echo __('Toggle galaxies');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle galaxies');?>"></span><?php echo __('Galaxy');?>
</button>
<button class="btn btn-inverse toggle qet" id="eventgraph_toggle" data-toggle-type="eventgraph" onclick="enable_interactive_graph();">
<button class="btn btn-inverse toggle qet" id="eventgraph_toggle" data-toggle-type="eventgraph">
<span class="fas fa-plus" title="<?php echo __('Toggle Event graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event graph');?>"></span><?php echo __('Event graph');?>
</button>
<button class="btn btn-inverse toggle qet" id="eventtimeline_toggle" data-toggle-type="eventtimeline" onclick="enable_timeline();">
<button class="btn btn-inverse toggle qet" id="eventtimeline_toggle" data-toggle-type="eventtimeline">
<span class="fas fa-plus" title="<?php echo __('Toggle Event timeline');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event timeline');?>"></span><?php echo __('Event timeline');?>
</button>
<button class="btn btn-inverse toggle qet" id="correlationgraph_toggle" data-toggle-type="correlationgraph" data-load-url="<?= $baseurl ?>/events/viewGraph/<?= h($event['Event']['id']) ?>">
@ -27,10 +27,10 @@
<span class="fas fa-minus" title="<?php echo __('Toggle discussions');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle discussions');?>"></span><?php echo __('Discussion');?>
</button>
</div>
<br />
<br />
<br>
<br>
<div id="pivots_div">
<?php if (sizeOf($allPivots) > 1) echo $this->element('pivot'); ?>
<?php if (count($allPivots) > 1) echo $this->element('pivot'); ?>
</div>
<div id="galaxies_div">
<span class="title-section"><?= __('Galaxies') ?></span>
@ -60,13 +60,12 @@
<div id="clusterrelation_div" class="info_container_eventgraph_network" style="display: none;" data-fullscreen="false">
</div>
<div id="attributes_div">
<?php echo $this->element('eventattribute'); ?>
<?= $this->element('eventattribute'); ?>
</div>
<div id="discussions_div">
</div>
</div>
<script type="text/javascript">
var showContext = false;
$(function () {
<?php
if (!Configure::check('MISP.disable_event_locks') || !Configure::read('MISP.disable_event_locks')) {
@ -77,8 +76,6 @@ $(function () {
);
}
?>
popoverStartup();
$(document.body).tooltip({
selector: 'span[title], td[title], time[title]',
placement: 'top',

View File

@ -3,7 +3,6 @@ $tr_class = '';
if (empty($context)) {
$context = 'event';
}
$linkClass = 'blue';
if ($event['Event']['id'] != $object['event_id']) {
if (!$isSiteAdmin && $event['extensionEvents'][$object['event_id']]['Orgc']['id'] != $me['org_id']) {
$mayModify = false;
@ -32,48 +31,36 @@ if (!empty($k)) {
$tr_class .= ' row_' . h($k);
}
$objectId = h($object['id']);
$objectId = (int) $object['id'];
$quickEdit = function($fieldName) use ($editScope, $object, $event) {
$quickEdit = function($fieldName) use ($mayModify, $object) {
if (!$mayModify) {
return ''; // currently it is not supported to create proposals trough quick edit
}
if ($object['deleted']) {
return ''; // deleted attributes are not editable
}
if ($editScope === 'ShadowAttribute') {
return ''; // currently it is not supported to create proposals trough quick edit
}
if ($fieldName === 'value' && ($object['type'] === 'attachment' || $object['type'] === 'malware-sample')) {
return '';
}
return " onmouseenter=\"quickEditHover(this, '$editScope', '{$object['id']}', '$fieldName', {$event['Event']['id']});\"";
return " data-edit-field=\"$fieldName\"";
}
?>
<tr id="Attribute_<?= $objectId ?>_tr" class="<?php echo $tr_class; ?>" tabindex="0">
<?php
if (($mayModify || !empty($extended)) && empty($disable_multi_select)):
?>
<td style="width:10px;" data-position="<?php echo 'attribute_' . $objectId ?>">
<?php
if ($mayModify):
?>
<input id="select_<?= $objectId ?>" class="select_attribute row_checkbox" type="checkbox" data-id="<?= $objectId ?>" aria-label="<?php echo __('Select attribute');?>" />
<?php
endif;
?>
<tr id="Attribute_<?= $objectId ?>_tr" data-primary-id="<?= $objectId ?>" class="<?php echo $tr_class; ?>" tabindex="0">
<?php if (($mayModify || !empty($extended)) && empty($disable_multi_select)): ?>
<td style="width:10px">
<?php if ($mayModify):?>
<input class="select_attribute" type="checkbox" data-id="<?= $objectId ?>" aria-label="<?php echo __('Select attribute');?>">
<?php endif; ?>
</td>
<?php
endif;
?>
<td class="short context hidden">
<?= $objectId ?>
</td>
<?php endif; ?>
<td class="short context hidden"><?= $objectId ?></td>
<td class="short context hidden uuid quickSelect"><?php echo h($object['uuid']); ?></td>
<td class="short context hidden">
<?php echo $this->element('/Events/View/seen_field', array('object' => $object)); ?>
</td>
<td class="short">
<?php echo date('Y-m-d', $object['timestamp']); ?>
</td>
<td class="short timestamp"><?= $this->Time->date($object['timestamp']) ?></td>
<?php
if (!empty($extended)):
?>
@ -100,31 +87,24 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
endif;
endif;
?>
&nbsp;
</td>
<td class="short"<?= $quickEdit('category') ?>>
<div id="Attribute_<?= $objectId ?>_category_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_category_solid" class="inline-field-solid">
<div class="inline-field-solid">
<?php echo h($object['category']); ?>
</div>
</td>
<td class="short"<?= $quickEdit('type') ?>>
<?php
if (!empty($object['object_relation'])):
?>
<?php if (!empty($object['object_relation'])):?>
<div class="bold"><?php echo h($object['object_relation']); ?>:</div>
<?php
endif;
?>
<div id="Attribute_<?= $objectId ?>_type_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_type_solid" class="inline-field-solid">
<?php endif; ?>
<div class="inline-field-solid">
<?php echo h($object['type']); ?>
</div>
</td>
<td id="Attribute_<?= $objectId ?>_container" class="showspaces limitedWidth shortish"<?= $quickEdit('value') ?>>
<div id="Attribute_<?= $objectId ?>_value_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_value_solid" class="inline-field-solid">
<div class="inline-field-solid">
<?php
$value = $this->element('/Events/View/value_field', array('object' => $object));
if (Configure::read('Plugin.Enrichment_hover_enable') && isset($modules) && isset($modules['hover_type'][$object['type']])) {
$commonDataFields = sprintf('data-object-type="Attribute" data-object-id="%s"', $objectId);
$spanExtra = Configure::read('Plugin.Enrichment_hover_popover_only') ? '' : sprintf(' class="eventViewAttributeHover" %s', $commonDataFields);
@ -132,20 +112,19 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
echo sprintf(
'<span%s>%s</span> %s',
$spanExtra,
$this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass)),
$value,
$popupButton
);
} else {
echo $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass));
echo $value;
}
?>
</div>
</td>
<td class="short">
<div class="attributeTagContainer">
<?php echo $this->element(
'ajaxTags',
array('attributeId' => $object['id'],
<?php echo $this->element('ajaxTags', array(
'attributeId' => $objectId,
'tags' => $object['AttributeTag'],
'tagAccess' => ($isSiteAdmin || $mayModify),
'localTagAccess' => ($isSiteAdmin || $mayModify || $me['org_id'] == $event['Event']['org_id'] || (int)$me['org_id'] === Configure::read('MISP.host_org_id')),
@ -160,7 +139,7 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
if (!empty($includeRelatedTags)) {
$element = '';
if (!empty($object['RelatedTags'])) {
$element = $this->element('ajaxAttributeTags', array('attributeId' => $object['id'], 'attributeTags' => $object['RelatedTags'], 'tagAccess' => false));
$element = $this->element('ajaxAttributeTags', array('attributeId' => $objectId, 'attributeTags' => $object['RelatedTags'], 'tagAccess' => false));
}
echo sprintf(
'<td class="shortish"><div %s>%s</div></td>',
@ -169,23 +148,21 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
);
}
?>
<?php $rowId = sprintf('attribute_%s_galaxy', h($objectId)); ?>
<td class="short" id="<?= $rowId ?>">
<td class="short" id="attribute_<?= $objectId ?>_galaxy">
<?php
echo $this->element('galaxyQuickViewNew', array(
'mayModify' => $mayModify,
'isAclTagger' => $isAclTagger,
'data' => (!empty($object['Galaxy']) ? $object['Galaxy'] : array()),
'event' => $event,
'target_id' => $object['id'],
'target_id' => $objectId,
'target_type' => 'attribute',
));
?>
</td>
<td class="showspaces bitwider"<?= $quickEdit('comment') ?>>
<div id="Attribute_<?= $objectId ?>_comment_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_comment_solid" class="inline-field-solid">
<?php echo nl2br(h($object['comment'])); ?>&nbsp;
<div class="inline-field-solid">
<?php echo nl2br(h($object['comment']), false); ?>
</div>
</td>
<td class="short" style="padding-top:3px;">
@ -195,7 +172,6 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
aria-label="<?php echo __('Toggle correlation');?>"
title="<?php echo __('Toggle correlation');?>"
type="checkbox"
data-attribute-id="<?= $objectId ?>"
<?php
echo $object['disable_correlation'] ? '' : ' checked';
echo ($mayChangeCorrelation && empty($event['Event']['disable_correlation'])) ? '' : ' disabled';
@ -204,7 +180,7 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
</td>
<td class="shortish">
<?php
if (!empty($event['RelatedAttribute'][$object['id']])) {
if (!empty($event['RelatedAttribute'][$objectId])) {
echo '<ul class="inline" style="margin:0">';
echo $this->element('Events/View/attribute_correlations', array(
'scope' => 'Attribute',
@ -306,20 +282,10 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
</ul>
</td>
<td class="short">
<div id="Attribute_<?= $objectId ?>_to_ids_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_to_ids_solid" class="inline-field-solid">
<input type="checkbox" class="toids-toggle" id="toids_toggle_<?= $objectId ?>" data-attribute-id="<?= $objectId ?>" aria-label="<?= __('Toggle IDS flag') ?>" title="<?= __('Toggle IDS flag') ?>"<?= $object['to_ids'] ? ' checked' : ''; ?><?= $mayModify ? '' : ' disabled' ?>>
</div>
<input type="checkbox" class="toids-toggle" id="toids_toggle_<?= $objectId ?>" aria-label="<?= __('Toggle IDS flag') ?>" title="<?= __('Toggle IDS flag') ?>"<?= $object['to_ids'] ? ' checked' : ''; ?><?= $mayModify ? '' : ' disabled' ?>>
</td>
<td class="short"<?= $quickEdit('distribution') ?>>
<?php
$turnRed = '';
if ($object['distribution'] == 0) {
$turnRed = 'style="color:red"';
}
?>
<div id="Attribute_<?= $objectId ?>_distribution_placeholder" class="inline-field-placeholder"></div>
<div id="Attribute_<?= $objectId ?>_distribution_solid" <?php echo $turnRed; ?> class="inline-field-solid">
<div class="inline-field-solid<?= $object['distribution'] == 0 ? ' red' : '' ?>">
<?php
if ($object['distribution'] == 4):
?>
@ -342,7 +308,7 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
}
if (!empty($includeDecayScore)): ?>
<td class="decayingScoreField">
<div id="Attribute_<?= $objectId ?>_score_solid" class="inline-field-solid">
<div class="inline-field-solid">
<?php echo $this->element('DecayingModels/View/attribute_decay_score', array('scope' => 'object', 'object' => $object, 'uselink' => true)); ?>
</div>
</td>
@ -354,25 +320,25 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
if ($object['deleted']):
if ($isSiteAdmin || $mayModify):
?>
<span class="fas fa-redo useCursorPointer" title="<?php echo __('Restore attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Restore attribute');?>" onClick="deleteObject('attributes', 'restore', '<?= $objectId ?>', '<?php echo h($event['Event']['id']); ?>');"></span>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Permanently delete attribute');?>" role="button" tabindex="0" aria-label="i<?php echo __('Permanently delete attribute');?>" onClick="deleteObject('attributes', 'delete', '<?= $objectId . '/true'; ?>', '<?php echo h($event['Event']['id']); ?>');"></span>
<span class="fas fa-redo useCursorPointer" title="<?php echo __('Restore attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Restore attribute');?>" onclick="deleteObject('attributes', 'restore', '<?= $objectId ?>')"></span>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Permanently delete attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Permanently delete attribute');?>" onclick="deleteObject('attributes', 'delete', '<?= $objectId . '/true'; ?>')"></span>
<?php
endif;
else:
if ($isAclAdd && ($isSiteAdmin || !$mayModify)):
if (isset($modules) && isset($modules['types'][$object['type']])):
?>
<span class="fas fa-asterisk useCursorPointer" role="button" tabindex="0" aria-label="<?php echo __('Query enrichment');?>" onClick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/ShadowAttribute');" title="<?php echo __('Propose enrichment');?>">&nbsp;</span>
<span class="fas fa-asterisk useCursorPointer" role="button" tabindex="0" aria-label="<?php echo __('Query enrichment');?>" onclick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/ShadowAttribute');" title="<?php echo __('Propose enrichment');?>">&nbsp;</span>
<?php
endif;
if (isset($cortex_modules) && isset($cortex_modules['types'][$object['type']])):
?>
<span class="icon-eye-open useCursorPointer" title="<?php echo __('Query Cortex');?>" role="button" tabindex="0" aria-label="<?php echo __('Query Cortex');?>" onClick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/ShadowAttribute/Cortex');" title="<?php echo __('Propose enrichment through Cortex');?>"></span>
<span class="icon-eye-open useCursorPointer" role="button" tabindex="0" aria-label="<?php echo __('Query Cortex');?>" onclick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/ShadowAttribute/Cortex');" title="<?php echo __('Propose enrichment through Cortex');?>"></span>
<?php
endif;
?>
<a href="<?php echo $baseurl;?>/shadow_attributes/edit/<?= $objectId ?>" title="<?php echo __('Propose Edit');?>" aria-label="<?php echo __('Propose Edit');?>" class="fa fa-comment useCursorPointer"></a>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Propose Deletion');?>" role="button" tabindex="0" aria-label="Propose deletion" onClick="deleteObject('shadow_attributes', 'delete', '<?= $objectId ?>', '<?php echo h($event['Event']['id']); ?>');"></span>
<a href="<?php echo $baseurl;?>/shadow_attributes/edit/<?= $objectId ?>" title="<?php echo __('Propose Edit');?>" aria-label="<?php echo __('Propose Edit');?>" class="fa fa-comment"></a>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Propose Deletion');?>" role="button" tabindex="0" aria-label="Propose deletion" onclick="deleteObject('shadow_attributes', 'delete', '<?= $objectId ?>')"></span>
<?php
if ($isSiteAdmin):
?>
@ -382,24 +348,24 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
if ($isSiteAdmin || $mayModify):
if (isset($modules) && isset($modules['types'][$object['type']])):
?>
<span class="fas fa-asterisk useCursorPointer" onClick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/Attribute');" title="<?php echo __('Add enrichment');?>" role="button" tabindex="0" aria-label="<?php echo __('Add enrichment');?>">&nbsp;</span>
<span class="fas fa-asterisk useCursorPointer" onclick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/Attribute');" title="<?php echo __('Add enrichment');?>" role="button" tabindex="0" aria-label="<?php echo __('Add enrichment');?>">&nbsp;</span>
<?php
endif;
if (isset($cortex_modules) && isset($cortex_modules['types'][$object['type']])):
?>
<span class="icon-eye-open useCursorPointer" onClick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/Attribute/Cortex');" title="<?php echo __('Add enrichment');?>" role="button" tabindex="0" aria-label="<?php echo __('Add enrichment via Cortex');?>"></span>
<span class="icon-eye-open useCursorPointer" onclick="simplePopup('<?php echo $baseurl;?>/events/queryEnrichment/<?= $objectId ?>/Attribute/Cortex');" title="<?php echo __('Add enrichment');?>" role="button" tabindex="0" aria-label="<?php echo __('Add enrichment via Cortex');?>"></span>
<?php
endif;
?>
<a href="<?php echo $baseurl;?>/attributes/edit/<?= $objectId ?>" title="<?php echo __('Edit');?>" aria-label="<?php echo __('Edit');?>" class="fa fa-edit useCursorPointer"></a>
<a href="<?php echo $baseurl;?>/attributes/edit/<?= $objectId ?>" title="<?php echo __('Edit');?>" aria-label="<?php echo __('Edit');?>" class="fa fa-edit"></a>
<?php
if (empty($event['Event']['publish_timestamp'])):
?>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Permanently delete attribute');?>" role="button" tabindex="0" aria-label="i<?php echo __('Permanently delete attribute');?>" onClick="deleteObject('attributes', 'delete', '<?= $objectId . '/true'; ?>', '<?php echo h($event['Event']['id']); ?>');"></span>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Permanently delete attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Permanently delete attribute');?>" onclick="deleteObject('attributes', 'delete', '<?= $objectId . '/true'; ?>')"></span>
<?php
else:
?>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Soft-delete attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Soft-delete attribute');?>" onClick="deleteObject('attributes', 'delete', '<?= $objectId ?>', '<?php echo h($event['Event']['id']); ?>');"></span>
<span class="fa fa-trash useCursorPointer" title="<?php echo __('Soft-delete attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Soft-delete attribute');?>" onclick="deleteObject('attributes', 'delete', '<?= $objectId ?>')"></span>
<?php
endif;
endif;

View File

@ -1,6 +1,4 @@
<?php
$linkClass = 'white';
$currentType = 'Object';
$tr_class = 'tableHighlightBorderTop borderBlue';
if ($event['Event']['id'] != $object['event_id']) {
if (!$isSiteAdmin && $event['extensionEvents'][$object['event_id']]['Orgc']['id'] != $me['org_id']) {
@ -12,8 +10,15 @@
if (!empty($k)) {
$tr_class .= ' row_' . h($k);
}
$quickEdit = function($fieldName) use ($mayModify) {
if (!$mayModify) {
return ''; // without permission it is not possible to edit object
}
return " data-edit-field=\"$fieldName\"";
};
$objectId = intval($object['id']);
?>
<tr id="Object_<?php echo $object['id']; ?>_tr" class="<?php echo $tr_class; ?>" tabindex="0">
<tr id="Object_<?= $objectId ?>_tr" data-primary-id="<?= $objectId ?>" class="<?php echo $tr_class; ?>" tabindex="0">
<?php
if ($mayModify || $extended):
?>
@ -21,16 +26,12 @@
<?php
endif;
?>
<td class="short context hidden">
<?php echo h($object['id']); ?>
</td>
<td class="short context hidden"><?= $objectId ?></td>
<td class="short context hidden uuid quickSelect"><?php echo h($object['uuid']); ?></td>
<td class="short context hidden">
<?php echo $this->element('/Events/View/seen_field', array('object' => $object)); ?>
</td>
<td class="short">
<?php echo date('Y-m-d', $object['timestamp']); ?>
</td>
<td class="short timestamp"><?= $this->Time->date($object['timestamp']) ?></td>
<?php
if ($extended):
?>
@ -51,13 +52,12 @@
endif;
endif;
?>
&nbsp;
</td>
<td colspan="<?= $includeRelatedTags ? 6 : 5 ?>">
<span class="bold"><?php echo __('Object name: ');?></span><?php echo h($object['name']);?>
<span class="fa fa-expand useCursorPointer" title="<?php echo __('Expand or Collapse');?>" role="button" tabindex="0" aria-label="<?php echo __('Expand or Collapse');?>" data-toggle="collapse" data-target="#Object_<?php echo h($object['id']); ?>_collapsible"></span>
<br />
<div id="Object_<?php echo $object['id']; ?>_collapsible" class="collapse">
<span class="fa fa-expand useCursorPointer" title="<?php echo __('Expand or Collapse');?>" role="button" tabindex="0" aria-label="<?php echo __('Expand or Collapse');?>" data-toggle="collapse" data-target="#Object_<?php echo $objectId ?>_collapsible"></span>
<br>
<div id="Object_<?= $objectId ?>_collapsible" class="collapse">
<span class="bold"><?php echo __('UUID');?>: </span><?php echo h($object['uuid']);?><br />
<span class="bold"><?php echo __('Meta-category: ');?></span><?php echo h($object['meta-category']);?><br />
<span class="bold"><?php echo __('Description: ');?></span><?php echo h($object['description']);?><br />
@ -77,21 +77,14 @@
}
?>
</td>
<td class="showspaces bitwider" onmouseenter="quickEditHover(this, 'Object', '<?php echo $object['id']; ?>', 'comment', <?php echo $event['Event']['id'];?>);">
<div id="Object_<?php echo $object['id']; ?>_comment_placeholder" class="inline-field-placeholder"></div>
<div id="Object_<?php echo $object['id']; ?>_comment_solid" class="inline-field-solid">
<?php echo nl2br(h($object['comment'])); ?>&nbsp;
<td class="showspaces bitwider"<?= $quickEdit('comment') ?>>
<div class="inline-field-solid">
<?= nl2br(h($object['comment']), false); ?>
</div>
</td>
<td colspan="4">&nbsp;
</td>
<td class="shortish" onmouseenter="quickEditHover(this, 'Object', '<?php echo $object['id']; ?>', 'distribution', <?php echo $event['Event']['id'];?>);">
<?php
$turnRed = '';
if ($object['distribution'] == 0) $turnRed = 'style="color:red"';
?>
<div id="<?php echo $currentType . '_' . $object['id'] . '_distribution_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType . '_' . $object['id'] . '_distribution_solid'; ?>" <?php echo $turnRed; ?> class="inline-field-solid">
<td colspan="4"></td>
<td class="shortish"<?= $quickEdit('distribution') ?>>
<div class="inline-field-solid<?= $object['distribution'] == 0 ? ' red' : '' ?>">
<?php
if ($object['distribution'] == 4):
?>
@ -100,11 +93,10 @@
else:
echo h($shortDist[$object['distribution']]);
endif;
?>&nbsp;
?>
</div>
</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td colspan="2"></td>
<?php
$paddedFields = array('includeSightingdb', 'includeDecayScore');
foreach ($paddedFields as $paddedField) {
@ -118,29 +110,27 @@
if ($mayModify) {
if (empty($object['deleted'])) {
echo sprintf(
'<a href="%s/objects/edit/%s" title="%s" aria-label="%s" class="fa fa-edit white useCursorPointer"></a> ',
'<a href="%s/objects/edit/%s" title="%s" aria-label="%s" class="fa fa-edit white"></a> ',
$baseurl,
h($object['id']),
$objectId,
__('Edit'),
__('Edit')
);
echo sprintf(
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onClick="%2$s"></span>',
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onclick="%2$s"></span>',
(empty($event['Event']['publish_timestamp']) ? __('Permanently delete object') : __('Soft delete object')),
sprintf(
'deleteObject(\'objects\', \'delete\', \'%s\', \'%s\');',
empty($event['Event']['publish_timestamp']) ? h($object['id']) . '/true' : h($object['id']),
h($event['Event']['id'])
'deleteObject(\'objects\', \'delete\', \'%s\');',
empty($event['Event']['publish_timestamp']) ? $objectId . '/true' : $objectId
)
);
} else {
echo sprintf(
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onClick="%2$s"></span>',
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onclick="%2$s"></span>',
__('Permanently delete object'),
sprintf(
'deleteObject(\'objects\', \'delete\', \'%s\', \'%s\');',
h($object['id']) . '/true',
h($event['Event']['id'])
'deleteObject(\'objects\', \'delete\', \'%s\');',
$objectId . '/true'
)
);
}
@ -161,5 +151,5 @@
'child' => $attrKey == $lastElement ? 'last' : true
));
}
echo '<tr class="objectAddFieldTr"><td><span class="fa fa-plus-circle objectAddField" title="' . __('Add an Object Attribute') .'" onclick="popoverPopup(this, ' . h($object['id']) . ', \'objects\', \'quickFetchTemplateWithValidObjectAttributes\')"></span></td></tr>';
echo '<tr class="objectAddFieldTr"><td><span class="fa fa-plus-circle objectAddField" title="' . __('Add an Object Attribute') .'" data-popover-popup="' . $baseurl . '/objects/quickFetchTemplateWithValidObjectAttributes/' . $objectId .'"></span></td></tr>';
}

View File

@ -36,8 +36,8 @@
?>
<tr id="proposal_<?= $object['id'] ?>_tr" class="<?php echo $tr_class; ?>">
<?php if ($mayModify): ?>
<td style="width:10px;" data-position="<?php echo h($object['objectType']) . '_' . h($object['id']); ?>">
<input id = "select_proposal_<?php echo $object['id']; ?>" class="select_proposal row_checkbox" type="checkbox" aria-label="<?php __('Select proposal');?>" data-id="<?php echo $object['id'];?>" />
<td style="width:10px">
<input class="select_proposal" type="checkbox" aria-label="<?php __('Select proposal');?>" data-id="<?php echo $object['id'];?>">
</td>
<?php endif; ?>
<td class="short context hidden">
@ -50,12 +50,10 @@
<?php echo $this->element('/Events/View/seen_field', array('object' => $object)); ?>
</td>
<td class="short">
<div id="<?php echo $currentType . '_' . $object['id'] . '_timestamp_solid'; ?>">
<?php
if (isset($object['timestamp'])) echo date('Y-m-d', $object['timestamp']);
if (isset($object['timestamp'])) echo $this->Time->date($object['timestamp']);
else echo '&nbsp';
?>
</div>
</td>
<?php
if ($extended):
@ -74,32 +72,18 @@
?>
</td>
<td class="short">
<div id="<?php echo $currentType . '_' . $object['id'] . '_category_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType . '_' . $object['id'] . '_category_solid'; ?>" class="inline-field-solid">
<?php echo h($object['category']); ?>
</div>
</td>
<td class="short">
<div id="<?php echo $currentType . '_' . $object['id'] . '_type_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType . '_' . $object['id'] . '_type_solid'; ?>" class="inline-field-solid">
<?php echo h($object['type']); ?>
</div>
</td>
<td id="<?php echo h($currentType) . '_' . h($object['id']) . '_container'; ?>" class="showspaces limitedWidth shortish">
<div id="<?php echo $currentType . '_' . $object['id'] . '_value_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType; ?>_<?php echo $object['id']; ?>_value_solid" class="inline-field-solid">
<?php
echo $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass));
?>
</div>
<?= $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass)); ?>
</td>
<td class="shortish">&nbsp;</td>
<td class="shortish">&nbsp;</td>
<td class="showspaces bitwider">
<div id="<?php echo $currentType . '_' . $object['id'] . '_comment_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType . '_' . $object['id'] . '_comment_solid'; ?>" class="inline-field-solid">
<?php echo nl2br(h($object['comment'])); ?>&nbsp;
</div>
<?php echo nl2br(h($object['comment']), false); ?>
</td>
<td class="short" style="padding-top:3px;">&nbsp;</td>
<td class="shortish">
@ -145,13 +129,7 @@
</ul>
</td>
<td class="short">
<div id="<?php echo $currentType . '_' . $object['id'] . '_to_ids_placeholder'; ?>" class="inline-field-placeholder"></div>
<div id="<?php echo $currentType . '_' . $object['id'] . '_to_ids_solid'; ?>" class="inline-field-solid">
<?php
if ($object['to_ids']) echo 'Yes';
else echo 'No';
?>
</div>
<?= $object['to_ids'] ? __('Yes') : __('No') ?>
</td>
<td class="shortish">&nbsp;</td>
<td class="shortish">&nbsp;</td>
@ -170,12 +148,12 @@
echo $this->Form->create('Shadow_Attribute', array('id' => 'ShadowAttribute_' . $object['id'] . '_accept', 'url' => $baseurl . '/shadow_attributes/accept/' . $object['id'], 'style' => 'display:none;'));
echo $this->Form->end();
?>
<span class="fas fa-check white useCursorPointer" title="<?php echo __('Accept Proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept proposal');?>" onClick="acceptObject('shadow_attributes', '<?php echo $object['id']; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
<span class="fas fa-check white useCursorPointer" title="<?php echo __('Accept Proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept proposal');?>" onclick="acceptObject('shadow_attributes', '<?php echo $object['id']; ?>');"></span>
<?php
}
if (($event['Orgc']['id'] == $me['org_id'] && $mayModify) || $isSiteAdmin || ($object['org_id'] == $me['org_id'])) {
?>
<span class="fa fa-trash white useCursorPointer" title="<?php echo __('Discard proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Discard proposal');?>" onClick="deleteObject('shadow_attributes', 'discard' ,'<?php echo $object['id']; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
<span class="fa fa-trash white useCursorPointer" title="<?php echo __('Discard proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Discard proposal');?>" onclick="deleteObject('shadow_attributes', 'discard' ,'<?php echo $object['id']; ?>');"></span>
<?php
}
?>

View File

@ -34,8 +34,8 @@
<?php
if ($mayModify):
?>
<td style="width:10px;" data-position="<?php echo h($object['objectType']) . '_' . h($object['id']); ?>">
<input id="select_proposal_<?php echo $object['id']; ?>" class="select_proposal row_checkbox" type="checkbox" data-id="<?php echo $object['id'];?>" />
<td style="width:10px;">
<input class="select_proposal" type="checkbox" data-id="<?php echo $object['id'];?>">
</td>
<?php
endif;
@ -73,12 +73,12 @@
echo $this->Form->create('Shadow_Attribute', array('id' => 'ShadowAttribute_' . $object['id'] . '_accept', 'url' => $baseurl . '/shadow_attributes/accept/' . $object['id'], 'style' => 'display:none;'));
echo $this->Form->end();
?>
<span class="fas fa-check white useCursorPointer" title="<?php echo __('Accept Proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept proposal');?>" onClick="acceptObject('shadow_attributes', '<?php echo $object['id']; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
<span class="fas fa-check white useCursorPointer" title="<?php echo __('Accept Proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept proposal');?>" onclick="acceptObject('shadow_attributes', '<?php echo $object['id']; ?>');"></span>
<?php
}
if (($event['Orgc']['id'] == $me['org_id'] && $mayModify) || $isSiteAdmin || ($object['org_id'] == $me['org_id'])) {
?>
<span class="fa fa-trash white useCursorPointer" title="<?php echo __('Discard proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Discard proposal');?>" onClick="deleteObject('shadow_attributes', 'discard' ,'<?php echo $object['id']; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
<span class="fa fa-trash white useCursorPointer" title="<?php echo __('Discard proposal');?>" role="button" tabindex="0" aria-label="<?php echo __('Discard proposal');?>" onclick="deleteObject('shadow_attributes', 'discard' ,'<?php echo $object['id']; ?>');"></span>
<?php
}
?>

View File

@ -24,23 +24,19 @@ if (isset($sightingsData['data'][$objectId])) {
}
?>
<td class="shortish">
<?php
if ($isAclSighting):
?>
<i class="far fa-thumbs-up useCursorPointer" title="<?php echo __('Add sighting');?>" role="button" tabindex="0" aria-label="<?php echo __('Add sighting');?>" onmouseover="flexibleAddSighting(this, '0', '<?= $objectId ?>', '<?php echo h($object['event_id']);?>', 'top');" onclick="addSighting('0', '<?= $objectId ?>', '<?php echo h($object['event_id']);?>');">&nbsp;</i>
<i class="far fa-thumbs-down useCursorPointer" title="<?php echo __('Mark as false-positive');?>" role="button" tabindex="0" aria-label="<?php echo __('Mark as false-positive');?>" onmouseover="flexibleAddSighting(this, '1', '<?= $objectId ?>', '<?php echo h($object['event_id']);?>', 'bottom');" onclick="addSighting('1', '<?= $objectId ?>', '<?php echo h($object['event_id']);?>');">&nbsp;</i>
<i class="fas fa-wrench useCursorPointer sightings_advanced_add" title="<?php echo __('Advanced sightings');?>" role="button" tabindex="0" aria-label="<?php echo __('Advanced sightings');?>" data-object-id="<?= $objectId ?>" data-object-context="attribute">&nbsp;</i>
<?php
endif;
?>
<span id="sightingCount_<?php echo $objectId; ?>" class="bold" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?= h($html) ?>">
<?php if ($isAclSighting): ?>
<i class="far fa-thumbs-up useCursorPointer" title="<?php echo __('Add sighting');?>" role="button" tabindex="0" aria-label="<?php echo __('Add sighting');?>" onmouseover="flexibleAddSighting(this, 0, <?= $objectId ?>, 'top');" onclick="addSighting(0, <?= $objectId ?>)"></i>
<i class="far fa-thumbs-down useCursorPointer" title="<?php echo __('Mark as false-positive');?>" role="button" tabindex="0" aria-label="<?php echo __('Mark as false-positive');?>" onmouseover="flexibleAddSighting(this, 1, <?= $objectId ?>, 'bottom');" onclick="addSighting(1, <?= $objectId ?>)"></i>
<i class="fas fa-wrench useCursorPointer sightings_advanced_add" title="<?php echo __('Advanced sightings');?>" role="button" tabindex="0" aria-label="<?php echo __('Advanced sightings');?>" data-object-id="<?= $objectId ?>" data-object-context="attribute"></i>
<?php endif; ?>
<b id="sightingCount_<?php echo $objectId; ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?= h($html) ?>">
(<span class="green"><?= $s ?></span>/<span class="red"><?= $f ?></span>/<span class="orange"><?= $e ?></span>)
</span>
</b>
</td>
<td class="short">
<?php
if (!empty($sightingsData['csv'][$objectId])) {
echo $this->element('sparkline', array('scope' => 'object', 'id' => $objectId, 'csv' => $sightingsData['csv'][$objectId]));
echo $this->element('sparkline_new', array('scope' => 'object', 'id' => $objectId, 'csv' => $sightingsData['csv'][$objectId]));
}
?>
</td>

View File

@ -2,10 +2,10 @@
<tr>
<?php if ($isSiteAdmin): ?>
<th>
<input class="select_all select" type="checkbox" title="<?php echo __('Select all');?>" role="button" tabindex="0" aria-label="<?php echo __('Select all events on current page');?>" onClick="toggleAllCheckboxes();" />&nbsp;
<input class="select_all select" type="checkbox" title="<?php echo __('Select all');?>" role="button" tabindex="0" aria-label="<?php echo __('Select all events on current page');?>" onClick="toggleAllCheckboxes();">
</th>
<?php else: ?>
<th style="padding-left:0px;padding-right:0px;">&nbsp;</th>
<th style="padding-left:0;padding-right:0;">&nbsp;</th>
<?php endif;?>
<th class="filter">
<?php echo $this->Paginator->sort('published');?>
@ -171,12 +171,12 @@
</td>
<?php if (in_array('timestamp', $columns, true)): ?>
<td class="short dblclickElement">
<?= $this->Time->time($event['Event']['timestamp']) ?>
<?= $this->Time->time($event['Event']['timestamp']) ?>
</td>
<?php endif; ?>
<?php if (in_array('publish_timestamp', $columns, true)): ?>
<td class="short dblclickElement">
<?= $this->Time->time($event['Event']['publish_timestamp']) ?>
<?= $this->Time->time($event['Event']['publish_timestamp']) ?>
</td>
<?php endif; ?>
<td class="dblclickElement">
@ -203,14 +203,14 @@
<td class="short action-links">
<?php
if (0 == $event['Event']['published'] && ($isSiteAdmin || ($isAclPublish && $event['Event']['orgc_id'] == $me['org_id']))) {
echo $this->Form->postLink('', array('action' => 'alert', $eventId), array('class' => 'black fa fa-upload', 'title' => __('Publish Event'), 'aria-label' => __('Publish Event')), __('Are you sure this event is complete and everyone should be informed?'));
echo sprintf('<a class="useCursorPointer fa fa-upload" title="%s" aria-label="%s" onclick="event.preventDefault();publishPopup(%s)"></a>', __('Publish Event'), __('Publish Event'), $eventId);
}
if ($isSiteAdmin || ($isAclModify && $event['Event']['user_id'] == $me['id']) || ($isAclModifyOrg && $event['Event']['orgc_id'] == $me['org_id'])):
?>
<a href="<?php echo $baseurl."/events/edit/".$eventId ?>" title="<?php echo __('Edit');?>" aria-label="<?php echo __('Edit');?>"><i class="black fa fa-edit"></i></a>
<?php
echo sprintf('<a class="useCursorPointer fa fa-trash" title="%s" aria-label="%s" onclick="deleteEvent(%s)"></a>', __('Delete'), __('Delete'), $eventId);
echo sprintf('<a class="useCursorPointer fa fa-trash" title="%s" aria-label="%s" onclick="event.preventDefault();deleteEventPopup(%s)"></a>', __('Delete'), __('Delete'), $eventId);
endif;
?>
<a href="<?php echo $baseurl."/events/view/".$eventId ?>" title="<?php echo __('View');?>" aria-label="<?php echo __('View');?>"><i class="fa black fa-eye"></i></a>
@ -226,11 +226,10 @@
}).click(function(e) {
if ($(this).is(':checked')) {
if (e.shiftKey) {
selectAllInbetween(lastSelected, this.id);
selectAllInbetween(lastSelected, this);
}
lastSelected = this.id;
lastSelected = this;
}
attributeListAnyAttributeCheckBoxesChecked();
});
$('.distributionNetworkToggle').each(function() {
@ -239,15 +238,4 @@
});
});
});
function deleteEvent(id) {
var message = "<?= __('Are you sure you want to delete #') ?>" + id + "?"
var url = '<?= $baseurl ?>/events/delete/' + id
if (confirm(message)) {
fetchFormDataAjax(url, function(formData) {
$('body').append($('<div id="temp" class="hidden"/>').html(formData));
$('#temp form').submit()
})
}
}
</script>

View File

@ -25,9 +25,10 @@
<?php
$addTagButton = '&nbsp;';
if ($full) {
$url = $baseurl . '/tags/selectTaxonomy/' . h($tagCollection['TagCollection']['id']) . '/tag_collection';
$addTagButton = sprintf(
'<button id="addTagButton" class="btn btn-inverse noPrint" style="line-height:10px; padding: 2px;" onClick="popoverPopup(this, %s);"><i class="fas fa-globe-americas"></i> +</button>',
sprintf("'%s/tag_collection', 'tags', 'selectTaxonomy'", h($tagCollection['TagCollection']['id']))
'<button id="addTagButton" class="btn addButton btn-inverse noPrint" data-popover-popup="%s"><i class="fas fa-globe-americas"></i> <i class="fas fa-plus"></i></button>',
$url
);
}
echo $addTagButton;

View File

@ -88,7 +88,7 @@
$span_delete = '';
if ($full || ($fullLocal && $tag['Tag']['local'])) {
$span_delete = sprintf(
'<span class="%s" title="%s" role="%s" tabindex="%s" aria-label="%s" onClick="%s">x</span>',
'<span class="%s" title="%s" role="%s" tabindex="%s" aria-label="%s" onclick="%s">x</span>',
'black-white tag useCursorPointer noPrint',
__('Remove tag'),
"button",
@ -107,43 +107,26 @@
$buttonData = array();
if ($full) {
$buttonData[] = sprintf(
'<button title="%s" role="button" tabindex="0" aria-label="%s" class="%s" style="%s" onClick="%s">%s</button>',
'<button title="%s" role="button" tabindex="0" aria-label="%s" class="%s" data-popover-popup="%s">%s</button>',
__('Add a tag'),
__('Add a tag'),
'addTagButton btn btn-inverse noPrint',
'line-height:10px; padding: 2px;',
sprintf(
"popoverPopup(this, '%s%s', '%s', '%s');",
$id,
($scope === 'event') ? '' : ('/' . $scope),
'tags',
'selectTaxonomy'
),
'<i class="fas fa-globe-americas"></i> +'
'addTagButton addButton btn btn-inverse noPrint',
$baseurl . '/tags/selectTaxonomy/' . $id . ($scope === 'event' ? '' : ('/' . $scope)),
'<i class="fas fa-globe-americas"></i> <i class="fas fa-plus"></i>'
);
}
if ($full || $fullLocal) {
$buttonData[] = sprintf(
'<button title="%s" role="button" tabindex="0" aria-label="%s" class="%s" style="%s" onClick="%s">%s</button>',
'<button title="%s" role="button" tabindex="0" aria-label="%s" class="%s" data-popover-popup="%s">%s</button>',
__('Add a local tag'),
__('Add a local tag'),
'addLocalTagButton btn btn-inverse noPrint',
'line-height:10px; padding: 2px;',
sprintf(
"popoverPopup(this, '%s%s', '%s', '%s')",
$id,
($scope === 'event') ? '' : ('/' . $scope),
'tags',
'selectTaxonomy/local:1'
),
'<i class="fas fa-user"></i> +'
'addLocalTagButton addButton btn btn-inverse noPrint',
$baseurl . '/tags/selectTaxonomy/local:1/' . $id . ($scope === 'event' ? '' : ('/' . $scope)),
'<i class="fas fa-user"></i> <i class="fas fa-plus"></i>'
);
}
if (!empty($buttonData)) {
$tagData .= sprintf(
'<span style="white-space:nowrap;">%s</span>',
implode(' ', $buttonData)
);
$tagData .= '<span style="white-space:nowrap">' . implode('', $buttonData) . '</span>';
}
echo sprintf(
'<span class="tag-list-container">%s</span>',
@ -156,11 +139,11 @@
$tagConflictData .= '<div class="text-container">';
foreach ($tagConflicts['global'] as $tagConflict) {
$tagConflictData .= sprintf(
'<strong>%s</strong></br>',
'<strong>%s</strong><br>',
h($tagConflict['conflict'])
);
foreach ($tagConflict['tags'] as $tag) {
$tagConflictData .= sprintf('<span class="apply_css_arrow nowrap">%s</span></br>', h($tag));
$tagConflictData .= sprintf('<span class="apply_css_arrow nowrap">%s</span><br>', h($tag));
}
}
$tagConflictData .= '</div></div></span>';
@ -171,14 +154,13 @@
$tagConflictData .= '<div class="text-container">';
foreach ($tagConflicts['local'] as $tagConflict) {
$tagConflictData .= sprintf(
'<strong>%s</strong></br>',
'<strong>%s</strong><br>',
h($tagConflict['conflict'])
);
foreach ($tagConflict['tags'] as $tag) {
$tagConflictData .= sprintf('<span class="apply_css_arrow nowrap">%s</span></br>', h($tag));
$tagConflictData .= sprintf('<span class="apply_css_arrow nowrap">%s</span><br>', h($tag));
}
}
$tagConflictData .= '</div></div></span>';
}
echo $tagConflictData;
?>

View File

@ -6,8 +6,6 @@
}
$urlHere = implode('/', $urlHere);
$urlHere = $baseurl . $urlHere;
$mayModify = ($isSiteAdmin || ($isAclModify && $event['Event']['user_id'] == $me['id'] && $event['Orgc']['id'] == $me['org_id']) || ($isAclModifyOrg && $event['Orgc']['id'] == $me['org_id']));
$mayPublish = ($isAclPublish && $event['Orgc']['id'] == $me['org_id']);
$mayChangeCorrelation = !Configure::read('MISP.completely_disable_correlation') && ($isSiteAdmin || ($mayModify && Configure::read('MISP.allow_disabling_correlation')));
$possibleAction = $mayModify ? 'attribute' : 'shadow_attribute';
$all = false;
@ -19,7 +17,7 @@
}
$fieldCount = 11;
$filtered = false;
if(isset($passedArgsArray)){
if (isset($passedArgsArray)){
if (count($passedArgsArray) > 0) {
$filtered = true;
}
@ -69,8 +67,7 @@
'label' => false,
));
echo $this->Form->end();
?>
<?php
echo $this->Form->create('ShadowAttribute', array('id' => 'accept_selected', 'url' => $baseurl . '/shadow_attributes/acceptSelected/' . $event['Event']['id']));
echo $this->Form->input('ids_accept', array(
'type' => 'text',
@ -79,8 +76,7 @@
'label' => false,
));
echo $this->Form->end();
?>
<?php
echo $this->Form->create('ShadowAttribute', array('id' => 'discard_selected', 'url' => $baseurl . '/shadow_attributes/discardSelected/' . $event['Event']['id']));
echo $this->Form->input('ids_discard', array(
'type' => 'text',
@ -111,7 +107,7 @@
if ($extended || ($mayModify && !empty($event['objects']))):
$fieldCount += 1;
?>
<th><input class="select_all" type="checkbox" title="<?php echo __('Select all');?>" role="button" tabindex="0" aria-label="<?php echo __('Select all attributes/proposals on current page');?>" onClick="toggleAllAttributeCheckboxes();" /></th>
<th><input class="select_all" type="checkbox" title="<?php echo __('Select all');?>" role="button" tabindex="0" aria-label="<?php echo __('Select all attributes/proposals on current page');?>" onclick="toggleAllAttributeCheckboxes()"></th>
<?php
endif;
?>
@ -227,9 +223,6 @@ attributes or the appropriate distribution level. If you think there is a mistak
var deleted = <?php echo (!empty($deleted)) ? '1' : '0';?>;
var includeRelatedTags = <?php echo (!empty($includeRelatedTags)) ? '1' : '0';?>;
$(function() {
$('.addGalaxy').click(function() {
addGalaxyListener(this);
});
<?php
if (isset($focus)):
?>
@ -242,18 +235,18 @@ attributes or the appropriate distribution level. If you think there is a mistak
$('.select_attribute').prop('checked', false).click(function(e) {
if ($(this).is(':checked')) {
if (e.shiftKey) {
selectAllInbetween(lastSelected, this.id);
selectAllInbetween(lastSelected, this);
}
lastSelected = this.id;
lastSelected = this;
}
attributeListAnyAttributeCheckBoxesChecked();
});
$('.select_proposal').prop('checked', false).click(function(e){
if ($(this).is(':checked')) {
if (e.shiftKey) {
selectAllInbetween(lastSelected, this.id);
selectAllInbetween(lastSelected, this);
}
lastSelected = this.id;
lastSelected = this;
}
attributeListAnyProposalCheckBoxesChecked();
});
@ -261,16 +254,6 @@ attributes or the appropriate distribution level. If you think there is a mistak
attributeListAnyAttributeCheckBoxesChecked();
attributeListAnyProposalCheckBoxesChecked();
});
$('.correlation-toggle').click(function() {
var attribute_id = $(this).data('attribute-id');
getPopup(attribute_id, 'attributes', 'toggleCorrelation', '', '#confirmation_box');
return false;
});
$('.toids-toggle').click(function() {
var attribute_id = $(this).data('attribute-id');
getPopup(attribute_id, 'attributes', 'toggleToIDS', '', '#confirmation_box');
return false;
});
$('.screenshot').click(function() {
screenshotPopup($(this).attr('src'), $(this).attr('title'));
});
@ -278,15 +261,13 @@ attributes or the appropriate distribution level. If you think there is a mistak
var selected = [];
var object_context = $(this).data('object-context');
var object_id = $(this).data('object-id');
if (object_id == 'selected') {
$(".select_attribute").each(function() {
if ($(this).is(":checked")) {
selected.push($(this).data("id"));
}
if (object_id === 'selected') {
$(".select_attribute:checked").each(function() {
selected.push($(this).data("id"));
});
object_id = selected.join('|');
}
url = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id + "/" + object_context;
var url = "<?php echo $baseurl; ?>" + "/sightings/advanced/" + object_id + "/" + object_context;
genericPopup(url, '#popover_box');
});
});

View File

@ -71,8 +71,9 @@
'title' => __('Tag selected Attributes'),
'class' => 'mass-select hidden',
'fa-icon' => 'tag',
'onClick' => 'popoverPopup',
'onClickParams' => array('this', 'selected/attribute', 'tags', 'selectTaxonomy')
'data' => [
'popover-popup' => $baseurl . '/tags/selectTaxonomy/selected/attribute',
],
),
array(
'id' => 'multi-galaxy-button',
@ -80,8 +81,9 @@
'class' => 'mass-select hidden',
'fa-icon' => 'rebel',
'fa-source' => 'fab',
'onClick' => 'popoverPopup',
'onClickParams' => array('this', 'selected/attribute/eventid:' . $eventId, 'galaxies', 'selectGalaxyNamespace')
'data' => [
'popover-popup' => $baseurl . '/galaxies/selectGalaxyNamespace/selected/attribute/eventid:' . $eventId,
],
),
array(
'id' => 'group-into-object-button',

View File

@ -123,21 +123,21 @@ echo $this->Form->end();
<?php endif; ?>
<?php
if ($editButtonsEnabled) {
$link = "$baseurl/galaxies/selectGalaxyNamespace/" . h($target_id) . "/" . h($target_type) . "/local:0";
echo sprintf(
'<button class="%s" data-target-type="%s" data-target-id="%s" data-local="false" role="button" tabindex="0" aria-label="' . __('Add new cluster') . '" title="' . __('Add new cluster') . '">%s</button>',
'useCursorPointer btn btn-inverse addGalaxy',
h($target_type),
h($target_id),
'<button class="%s" data-popover-popup="%s" role="button" tabindex="0" aria-label="' . __('Add new cluster') . '" title="' . __('Add new cluster') . '">%s</button>',
'useCursorPointer addButton btn btn-inverse',
$link,
'<i class="fas fa-globe-americas"></i> <i class="fas fa-plus"></i>'
);
}
if ($editButtonsLocalEnabled) {
$link = "$baseurl/galaxies/selectGalaxyNamespace/" . h($target_id) . "/" . h($target_type) . "/local:1";
echo sprintf(
'<button class="%s" data-target-type="%s" data-target-id="%s" data-local="true" role="button" tabindex="0" aria-label="' . __('Add new local cluster') . '" title="' . __('Add new local cluster') . '">%s</button>',
'useCursorPointer btn btn-inverse addGalaxy',
h($target_type),
h($target_id),
'<button class="%s" data-popover-popup="%s" role="button" tabindex="0" aria-label="' . __('Add new local cluster') . '" title="' . __('Add new local cluster') . '">%s</button>',
'useCursorPointer addButton btn btn-inverse',
$link,
'<i class="fas fa-user"></i> <i class="fas fa-plus"></i>'
);
}

View File

@ -4,6 +4,7 @@
<span id="pull_tags_NOT" style="display:none;"><?php echo __('Events with the following tags blocked'); ?>: <span id="pull_tags_NOT_text" style="color:red;"></span><br /></span>
<span id="pull_orgs_OR" style="display:none;"><?php echo __('Events with the following organisations allowed'); ?>: <span id="pull_orgs_OR_text" style="color:green;"></span><br /></span>
<span id="pull_orgs_NOT" style="display:none;"><?php echo __('Events with the following organisations blocked'); ?>: <span id="pull_orgs_NOT_text" style="color:red;"></span><br /></span>
<span id="pull_url_params" style="display:none;"><?php echo __('Additional parameters: '); ?><span id="pull_url_params_text" style="color:green;"></span><br /></span>
<span id="pull_modify" class="btn btn-inverse" style="line-height:10px; padding: 4px 4px;"><?php echo __('Modify'); ?></span><br /><br />
<div id="hiddenRuleForms">
@ -23,7 +24,8 @@
'context' => $this->Form->defaultModel,
'allTags' => $fieldData['tags'],
'allOrganisations' => $fieldData['orgs'],
'ruleObject' => $pullRules
'ruleObject' => $pullRules,
'coreMirrorHints' => $supportedUrlparams,
])
]
],

View File

@ -23,13 +23,17 @@
continue;
}
if (isset($action['complex_requirement'])) {
if (isset($action['complex_requirement']['options']['datapath'])) {
foreach ($action['complex_requirement']['options']['datapath'] as $name => $path) {
$action['complex_requirement']['options']['datapath'][$name] = empty(Hash::extract($row, $path)[0]) ? null : Hash::extract($row, $path)[0];
if ($action['complex_requirement'] instanceof Closure) {
$requirementMet = $action['complex_requirement']($row);
} else {
if (isset($action['complex_requirement']['options']['datapath'])) {
foreach ($action['complex_requirement']['options']['datapath'] as $name => $path) {
$action['complex_requirement']['options']['datapath'][$name] = empty(Hash::extract($row, $path)[0]) ? null : Hash::extract($row, $path)[0];
}
}
$options = isset($action['complex_requirement']['options']) ? $action['complex_requirement']['options'] : [];
$requirementMet = $action['complex_requirement']['function']($row, $options);
}
$options = isset($action['complex_requirement']['options']) ? $action['complex_requirement']['options'] : array();
$requirementMet = $action['complex_requirement']['function']($row, $options);
if (!$requirementMet) {
continue;
}

View File

@ -10,15 +10,13 @@ if ($quickedit) {
$distributionLevel = (Hash::extract($row, $field['data_path'])[0]);
echo sprintf('<div %s>', $quickedit ? sprintf(
" onmouseenter=\"quickEditHover(this, '%s', %s, 'distribution', %s);\"",
" onmouseenter=\"quickEditHover(this, '%s', %s, 'distribution');\"",
$scope,
$objectId,
$event['id']
$objectId
) : '');
if ($quickedit) {
echo sprintf("<div id='%s_%s_distribution_placeholder' class='inline-field-placeholder'></div>", $scope, $objectId);
echo sprintf("<div id='%s_%s_distribution_solid' class='inline-field-solid'>", $scope, $objectId);
echo "<div class='inline-field-solid'>";
}
echo sprintf(

View File

@ -29,12 +29,12 @@ if (isset($sightings['data'][$objectId])) {
if ($isAclSighting) :
?>
<i class="far fa-thumbs-up useCursorPointer" title="<?php echo __('Add sighting'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Add sighting'); ?>" onmouseover="flexibleAddSighting(this, '0', '<?= $objectId ?>', '<?php echo h($object['event_id']); ?>', 'top');" onclick="addSighting('0', '<?= $objectId ?>', '<?php echo h($object['event_id']); ?>');">&nbsp;</i>
<i class="far fa-thumbs-down useCursorPointer" title="<?php echo __('Mark as false-positive'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Mark as false-positive'); ?>" onmouseover="flexibleAddSighting(this, '1', '<?= $objectId ?>', '<?php echo h($object['event_id']); ?>', 'bottom');" onclick="addSighting('1', '<?= $objectId ?>', '<?php echo h($object['event_id']); ?>');">&nbsp;</i>
<i class="fas fa-wrench useCursorPointer sightings_advanced_add" title="<?php echo __('Advanced sightings'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Advanced sightings'); ?>" data-object-id="<?= $objectId ?>" data-object-context="attribute">&nbsp;</i>
<i class="far fa-thumbs-up useCursorPointer" title="<?php echo __('Add sighting'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Add sighting'); ?>" onmouseover="flexibleAddSighting(this, 0, <?= $objectId ?>, 'top');" onclick="addSighting(0, <?= $objectId ?>);"></i>
<i class="far fa-thumbs-down useCursorPointer" title="<?php echo __('Mark as false-positive'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Mark as false-positive'); ?>" onmouseover="flexibleAddSighting(this, 1, <?= $objectId ?>, 'bottom');" onclick="addSighting(1, '<?= $objectId ?>');"></i>
<i class="fas fa-wrench useCursorPointer sightings_advanced_add" title="<?php echo __('Advanced sightings'); ?>" role="button" tabindex="0" aria-label="<?php echo __('Advanced sightings'); ?>" data-object-id="<?= $objectId ?>" data-object-context="attribute"></i>
<?php
endif;
?>
<span id="sightingCount_<?php echo $objectId; ?>" class="bold" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?= h($html) ?>">
<b id="sightingCount_<?php echo $objectId; ?>" data-placement="top" data-toggle="popover" data-trigger="hover" data-content="<?= h($html) ?>">
(<span class="green"><?= $s ?></span>/<span class="red"><?= $f ?></span>/<span class="orange"><?= $e ?></span>)
</span>
</b>

View File

@ -6,18 +6,30 @@
* to fetch it.
*
*/
$data = Hash::extract($row, $field['data_path']);
$seed = mt_rand();
$checkboxId = 'GenericToggle-' . $seed;
$checkboxClass = empty($field['checkbox_class']) ? 'genericCheckbox' : h($field['checkbox_class']);
$tempboxId = 'TempBox-' . $seed;
echo sprintf(
'<input type="checkbox" id="%s" class="%s" %s><span id="%s" class="hidden">',
$checkboxId,
$checkboxClass,
empty($data[0]) ? '' : 'checked',
$tempboxId
);
$data = Hash::extract($row, $field['data_path']);
$seed = mt_rand();
$checkboxId = 'GenericToggle-' . $seed;
$checkboxClass = empty($field['checkbox_class']) ? 'genericCheckbox' : h($field['checkbox_class']);
$tempboxId = 'TempBox-' . $seed;
$params = [];
if (!empty($data[0])) {
$params[] = 'checked';
}
if (!empty($field['disabled'])) {
$params[] = 'disabled';
}
$params = empty($params) ? '' : ' ' . implode(' ', $params);
echo sprintf(
'<input type="checkbox" id="%s" class="%s"%s><span id="%s" class="hidden"></span>',
$checkboxId,
$checkboxClass,
$params,
$tempboxId
);
if (empty($field['disabled'])):
?>
<script type="text/javascript">
$(function() {
@ -71,3 +83,4 @@ $(function() {
});
});
</script>
<?php endif; ?>

View File

@ -9,7 +9,7 @@ if (!isset($data['requirement']) || $data['requirement']) {
}
$onClickParams = implode(',', $onClickParams);
$onClick = sprintf(
'onClick = "%s%s"',
'onclick="%s%s"',
(empty($data['url'])) ? 'event.preventDefault();' : '',
(!empty($data['onClick']) ? sprintf(
'%s(%s)',
@ -28,7 +28,6 @@ if (!isset($data['requirement']) || $data['requirement']) {
);
}
}
$dataFields = implode(' ', $dataFields);
echo sprintf(
'<li><a class="%s %s" id="%s" href="%s" %s %s %s %s>%s%s%s</a></li>',
empty($data['class']) ? '' : h($data['class']),
@ -36,7 +35,7 @@ if (!isset($data['requirement']) || $data['requirement']) {
empty($data['id']) ? '' : h($data['id']),
empty($data['url']) ? '#' : h($data['url']), // prevent default is passed if the url is not set
empty($onClick) ? '' : $onClick, // pass $data['onClick'] for the function name to call and $data['onClickParams'] for the parameter list
empty($dataFields) ? '' : $dataFields,
empty($dataFields) ? '' : implode(' ', $dataFields),
empty($data['title']) ? '' : sprintf('title="%s"', h($data['title'])),
!empty($data['text']) ? '' : (!empty($data['title']) ? sprintf('aria-label="%s"', h($data['title'])) : ''),
empty($data['fa-icon']) ? '' : sprintf('<i class="fa fa-%s"></i>', $data['fa-icon']), // this has to be sanitised beforehand!

View File

@ -32,15 +32,20 @@
);
}
}
$dataFields = implode(' ', $dataFields);
$classes = ['btn', 'btn-small'];
$classes[] = empty($data['active']) ? 'btn-inverse' : 'btn-primary';
if (!empty($data['class'])) {
$classes[] = $data['class'];
}
echo sprintf(
'<a class="btn btn-small %s %s" %s href="%s" %s %s %s %s %s>%s%s%s %s</a>',
empty($data['class']) ? '' : h($data['class']),
empty($data['active']) ? 'btn-inverse' : 'btn-primary', // Change the default class for highlighted/active toggles here
'<a class="%s" %s href="%s" %s %s %s %s %s>%s%s%s %s</a>',
implode(' ', $classes),
empty($data['id']) ? '' : 'id="' . h($data['id']) . '"',
empty($data['url']) ? '#' : h($data['url']), // prevent default is passed if the url is not set
empty($onClick) ? '' : $onClick, // pass $data['onClick'] for the function name to call and $data['onClickParams'] for the parameter list
empty($dataFields) ? '' : $dataFields,
empty($dataFields) ? '' : implode(' ', $dataFields),
empty($data['title']) ? '' : sprintf('title="%s"', h($data['title'])),
empty($data['style']) ? '' : sprintf('style="%s"', h($data['style'])),
!empty($data['text']) ? '' : (!empty($data['title']) ? sprintf('aria-label="%s"', h($data['title'])) : ''),

View File

@ -98,10 +98,13 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
'url' => $baseurl . '/events/edit/' . $eventId,
'text' => __('Edit Event')
));
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'url' => $baseurl . '/events/delete/' . $eventId,
'text' => __('Delete Event'),
'message' => __('Are you sure you want to delete event #%s?', $eventId)
'onClick' => array(
'function' => 'deleteEventPopup',
'params' => [$eventId]
),
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'addAttribute',
@ -337,10 +340,10 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
),
'text' => __('Import from…')
));
if ($canAccess('servers', 'rest')) {
if ($canAccess('api', 'rest')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'rest',
'url' => $baseurl . '/servers/rest',
'url' => $baseurl . '/api/rest',
'text' => __('REST client')
));
}
@ -1606,17 +1609,15 @@ $divider = $this->element('/genericElements/SideMenu/side_menu_divider');
case 'api':
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'openapi',
'url' => $baseurl . '/servers/openapi',
'url' => $baseurl . '/api/openapi',
'text' => __('OpenAPI')
));
if ($isAclAdd) {
if ($canAccess('servers', 'rest')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'rest',
'url' => $baseurl . '/servers/rest',
'text' => __('REST client')
));
}
if ($canAccess('api', 'rest')) {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'rest',
'url' => $baseurl . '/api/rest',
'text' => __('REST client')
));
}
break;
}

View File

@ -44,7 +44,7 @@ if (!empty($onClick)) {
$params .= "'" . h($param) . "'";
}
}
$a .= sprintf(' onclick="%s(%s)"', $onClick['function'], $params);
$a .= sprintf(' onclick="event.preventDefault();%s(%s)"', $onClick['function'], $params);
}
if (!empty($download)) {
$a .= ' download="' . h($download) . '"';

View File

@ -1,25 +1,25 @@
<?php
$links = [];
foreach ($event['warnings'] as $id => $name) {
$links[] = sprintf(
'<a href="%s/warninglists/view/%s">%s</a>',
$baseurl,
h($id),
h($name)
);
}
echo sprintf(
'<div class="warning_container">%s%s</div>',
sprintf(
'<h4 class="red">%s</h4>',
sprintf(
'%s<a href="#attributeList" title="%s" onclick="toggleBoolFilter(\'%s/events/view/%s\');">%s</a>',
__('Warning: Potential false positives'),
__('Show just attributes that have warnings'),
$baseurl,
h($event['Event']['id']),
__(' (show)')
)
),
implode('<br />', $links)
$links = [];
foreach ($event['warnings'] as $id => $name) {
$links[] = sprintf(
'<a href="%s/warninglists/view/%s">%s</a>',
$baseurl,
(int)$id,
h($name)
);
}
echo sprintf(
'<div class="warning_container">%s%s</div>',
sprintf(
'<h4>%s</h4>',
sprintf(
'%s <a href="#attributeList" title="%s" onclick="toggleBoolFilter(\'%s/events/view/%s\', \'warning\');">(%s)</a>',
__('Warning: Potential false positives'),
__('Show just attributes that have warnings'),
$baseurl,
(int)$event['Event']['id'],
__('show')
)
),
implode('<br>', $links)
);

View File

@ -12,8 +12,8 @@
if ($taxonomy['Taxonomy']['exclusive']) {
$conflictHtmlInternal[] = sprintf(
'<li>%s</li>',
sprintf(
('%s is an exclusive taxonomy. Only one Tag of this taxonomy is allowed on an element.'),
__(
'%s is an exclusive taxonomy. Only one Tag of this taxonomy is allowed on an element.',
sprintf('<strong>%s</strong>', h($taxonomy['Taxonomy']['namespace']))
)
);
@ -21,8 +21,8 @@
foreach ($taxonomy['TaxonomyPredicate'] as $predicate) {
$conflictHtmlInternal[] = sprintf(
'<li>%s</li>',
sprintf(
('%s is an exclusive taxonomy predicate. Only one Tag of this predicate is allowed on an element'),
__(
'%s is an exclusive taxonomy predicate. Only one Tag of this predicate is allowed on an element',
sprintf('<strong>%s</strong>', h($predicate['value']))
)
);
@ -35,7 +35,7 @@
}
echo sprintf(
'<div class="warning_container"><h4 class="red">%s</h4>%s</div>',
'<div class="warning_container"><h4>%s</h4>%s</div>',
__('Warning: Taxonomy inconsistencies'),
$conflictHtml
);

View File

@ -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(

View File

@ -488,12 +488,12 @@
'children' => array(
array(
'text' => __('OpenAPI'),
'url' => $baseurl . '/servers/openapi'
'url' => $baseurl . '/api/openapi'
),
array(
'text' => __('REST client'),
'url' => $baseurl . '/servers/rest',
'requirement' => $canAccess('servers', 'rest')
'url' => $baseurl . '/api/rest',
'requirement' => $canAccess('api', 'rest')
)
)
)

View File

@ -81,7 +81,7 @@
</div>
<?php
if (!empty(Configure::read('MISP.enable_synchronisation_filtering_on_type'))) {
if ($pull_scope == 'server' && !empty(Configure::read('MISP.enable_synchronisation_filtering_on_type'))) {
echo $this->element('serverRuleElements/rules_filtering_type', [
'technique' => 'pull',
'allowEmptyOptions' => true,
@ -99,6 +99,7 @@ echo $this->element('genericElements/assetLoader', array(
'js' => array(
'codemirror/codemirror',
'codemirror/modes/javascript',
'codemirror/addons/show-hint',
'codemirror/addons/closebrackets',
'codemirror/addons/lint',
'codemirror/addons/jsonlint',
@ -114,6 +115,7 @@ echo $this->element('genericElements/assetLoader', array(
<script>
var pullRemoteRules404Error = '<?= __('Connection error or the remote version is not supporting remote filter lookups (v2.4.142+). Make sure that the remote instance is accessible and that it is up to date.') ?>'
var coreMirrorHints = <?= json_encode(!empty($coreMirrorHints) ? $coreMirrorHints : []) ?>;
var cm;
$(function() {
var serverID = "<?= isset($id) ? $id : '' ?>"
@ -194,6 +196,28 @@ echo $this->element('genericElements/assetLoader', array(
});
}
function jsonHints() {
var cur = cm.getCursor()
var token = cm.getTokenAt(cur)
if (token.type != 'string property' && token.type != 'string') {
return
}
if (cm.getMode().helperType !== "json") return;
token.state = cm.state;
token.line = cur.line
if (/\"([^\"]*)\"/.test(token.string)) {
token.end = cur.ch;
token.string = token.string.slice(1, cur.ch - token.start);
}
return {
list: token.type == 'string property' ? coreMirrorHints : [],
from: CodeMirror.Pos(cur.line, token.start + 1),
to: CodeMirror.Pos(cur.line, token.end)
}
}
function setupCodeMirror() {
var cmOptions = {
mode: "application/json",
@ -205,10 +229,23 @@ echo $this->element('genericElements/assetLoader', array(
showCursorWhenSelecting: true,
lineWrapping: true,
autoCloseBrackets: true,
extraKeys: {
"Esc": function(cm) {},
"Ctrl-Space": "autocomplete",
},
hintOptions: {
completeSingle: false,
hint: jsonHints
},
}
cm = CodeMirror.fromTextArea(document.getElementById('urlParams'), cmOptions);
cm.on("keyup", function(cm, event) {
$('#urlParams').val(cm.getValue())
if (!cm.state.completionActive && /*Enables keyboard navigation in autocomplete list*/
event.keyCode != 13) {
/*Enter - do not open autocomplete list just after item has been selected in it*/
cm.showHint()
}
});
}
})
@ -220,4 +257,8 @@ echo $this->element('genericElements/assetLoader', array(
width: 100%;
border: 1px solid #ddd;
}
.CodeMirror-hints {
z-index: 1050;
}
</style>

View File

@ -0,0 +1,6 @@
<?php if (!empty($csv)): ?>
<div id="spark_<?php echo (isset($scope) ? h($scope) . '_' : ''); ?><?php echo h($id); ?>"></div>
<script>
sparkline('#spark_<?php echo (isset($scope) ? h($scope) . '_' : ''); ?><?php echo h($id); ?>', "<?= $csv ?>");
</script>
<?php endif; ?>

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1,14 @@
<?php
$body = str_replace('$password', $password, $body);
$body = str_replace('$username', $user['User']['email'], $body);
$body = str_replace('\n', PHP_EOL, $body);
$resolveVars = [
'$contact' => 'MISP.contact',
'$org' => 'MISP.org',
'$misp' => 'MISP.baseurl'
];
foreach ($resolveVars as $k => $v) {
$v = Configure::read($v);
$body= str_replace($k, $v, $body);
}
echo $body;

View File

@ -2,9 +2,9 @@
<?php
echo $this->Form->create('EventBlocklist', array('style' => 'margin:0px;', 'id' => 'PromptForm'));
echo $this->Form->input('ids', array(
'type' => 'hidden',
'div' => 'hidden',
'value' => json_encode($event_ids)
'type' => 'hidden',
'div' => 'hidden',
'value' => json_encode($event_ids),
));
?>
<legend><?php echo __('Delete blocklisted events'); ?></legend>
@ -13,7 +13,7 @@
<table>
<tr>
<td style="vertical-align:top">
<span role="button" tabindex="0" aria-label="Publish" title="Publish" id="PromptYesButton" class="btn btn-primary" onClick="submitPublish()">Yes</span>
<button role="button" tabindex="0" aria-label="Delete" title="Delete" id="PromptYesButton" class="btn btn-primary">Yes</button>
</td>
<td style="width:540px;">
</td>
@ -23,7 +23,5 @@
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

View File

@ -13,29 +13,29 @@
'type' => 'simple',
'children' => array(
array(
'onClick' => 'openGenericModal',
'onClickParams' => [$baseurl . '/eventReports/add/' . h($event_id)],
'url' => $baseurl . '/eventReports/add/' . h($event_id),
'active' => true,
'text' => __('Add Event Report'),
'fa-icon' => 'plus',
'class' => 'modal-open',
'requirement' => $canModify,
),
array(
'onClick' => 'openGenericModal',
'onClickParams' => [$baseurl . '/eventReports/importReportFromUrl/' . h($event_id)],
'url' => $baseurl . '/eventReports/importReportFromUrl/' . h($event_id),
'active' => true,
'text' => __('Import from URL'),
'title' => __('Content for this URL will be downloaded and converted to Markdown'),
'fa-icon' => 'link',
'class' => 'modal-open',
'requirement' => $canModify && $importModuleEnabled,
),
array(
'onClick' => 'openGenericModal',
'onClickParams' => [$baseurl . '/eventReports/reportFromEvent/' . h($event_id)],
'url' => $baseurl . '/eventReports/reportFromEvent/' . h($event_id),
'active' => true,
'text' => __('Generate report from Event'),
'title' => __('Based on filters, create a report summarizing the event'),
'fa-icon' => 'list-alt',
'class' => 'modal-open',
'requirement' => $canModify,
),
)
@ -114,18 +114,9 @@
'icon' => 'trash',
'onclick' => 'simplePopup(\'' . $baseurl . '/event_reports/delete/[onclick_params_data_path]\');',
'onclick_params_data_path' => 'EventReport.id',
'complex_requirement' => array(
'function' => function ($row, $options) {
return ($options['me']['Role']['perm_site_admin'] || $options['me']['org_id'] == $options['datapath']['orgc']) && !$options['datapath']['deleted'];
},
'options' => array(
'me' => $me,
'datapath' => array(
'orgc' => 'EventReport.orgc_id',
'deleted' => 'EventReport.deleted'
)
)
),
'complex_requirement' => function (array $row) use ($me) {
return ($me['Role']['perm_site_admin'] || $me['org_id'] == $row['EventReport']['orgc_id']) && !$row['EventReport']['deleted'];
},
),
array(
'title' => __('Restore report'),
@ -134,25 +125,15 @@
'icon' => 'trash-restore',
'postLink' => true,
'postLinkConfirm' => __('Are you sure you want to restore the Report?'),
'complex_requirement' => array(
'function' => function ($row, $options) {
return ($options['me']['Role']['perm_site_admin'] || $options['me']['org_id'] == $options['datapath']['orgc']) && $options['datapath']['deleted'];
},
'options' => array(
'me' => $me,
'datapath' => array(
'orgc' => 'EventReport.orgc_id',
'deleted' => 'EventReport.deleted'
)
)
),
'complex_requirement' => function (array $row) use ($me) {
return ($me['Role']['perm_site_admin'] || $me['org_id'] == $row['EventReport']['orgc_id']) && $row['EventReport']['deleted'];
}
),
)
)
));
?>
</div>
<script>
var loadingSpanAnimation = '<span id="loadingSpan" class="fa fa-spin fa-spinner" style="margin-left: 5px;"></span>';
$(function() {

View File

@ -11,12 +11,3 @@ echo $this->element('galaxyQuickViewNew', [
'target_id' => $scope == 'event' ? $object['Event']['id'] : $object['Attribute']['id'],
'target_type' => $scope
]);
?>
<script type="text/javascript">
var showContext = false;
$(function () {
$('.addGalaxy').click(function() {
addGalaxyListener(this);
});
});
</script>

View File

@ -1,23 +1,22 @@
<div class="confirmation">
<?php
echo $this->Form->create('Event', array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => $baseurl . '/events/delete'));
echo $this->Form->hidden('id');
echo $this->Form->hidden('id');
?>
<legend><?php echo __('Event Deletion');?></legend>
<div style="padding-left:5px;padding-right:5px;padding-bottom:5px;">
<?php
$message = __('Are you sure you want to delete ');
if (count($idArray) > 1) {
$message .= count($idArray) . ' Events?';
$message = __('Are you sure you want to delete %s events?', count($idArray));
} else {
$message .= __(' Event #') . $idArray[0] . '?';
$message = __('Are you sure you want to delete event #%s?', $idArray[0]);
}
?>
<p><?php echo h($message); ?></p>
<p><?= h($message); ?></p>
<table>
<tr>
<td style="vertical-align:top">
<span class="btn btn-primary" title="<?php echo __('Accept');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept');?>" id="PromptYesButton" onClick="submitMassEventDelete();"><?php echo __('Yes');?></span>
<button class="btn btn-primary" title="<?php echo __('Accept');?>" role="button" tabindex="0" aria-label="<?php echo __('Accept');?>" id="PromptYesButton"><?php echo __('Yes');?></button>
</td>
<td style="width:540px;">
</td>
@ -27,7 +26,5 @@
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

View File

@ -1,41 +1,40 @@
<div class="confirmation">
<?php
echo $this->Form->create('Event', array('style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => $baseurl . '/events/' . $type . '/' . $id));
$extraTitle = "";
if ($type == 'publish') $extraTitle = ' (no email)';
$message = __('Publish Event%s', $extraTitle);
echo $this->Form->create('Event', ['style' => 'margin:0px;', 'id' => 'PromptForm', 'url' => $baseurl . '/events/' . $type . '/' . $id]);
if ($type === 'unpublish') {
$message = __('Unpublish Event%s', $extraTitle);
$message = __('Unpublish Event');
$buttonTitle = __('Unpublish');
} else {
$extraTitle = $type === 'publish' ? ' (no email)' : '';
$message = __('Publish Event%s', $extraTitle);
$buttonTitle = __('Publish');
}
?>
<legend><?php echo $message;?></legend>
<legend><?= $message ?></legend>
<div style="padding-left:5px;padding-right:5px;padding-bottom:5px;">
<?php
if ($type == 'alert') {
echo '<p>' . __('Are you sure this event is complete and everyone should be informed?') . '</p>';
<p><?php
if ($type === 'alert') {
echo __('Are you sure this event is complete and everyone should be informed?');
} else if ($type === 'unpublish') {
echo '<p>' . __('Are you sure you wish to unpublish the event?') . '</p>';
echo __('Are you sure you wish to unpublish the event?');
} else if ($type === 'publishSightings') {
echo '<p>' . __('Are you sure you wish publish and synchronise all sightings attached to this event?') . '</p>';
echo __('Are you sure you wish publish and synchronise all sightings attached to this event?');
} else {
echo '<p>' . __('Publish but do NOT send alert email? Only for minor changes!') . '</p>';
echo __('Publish but do NOT send alert email? Only for minor changes!');
}
?>
?></p>
<table>
<tr>
<td style="vertical-align:top">
<span role="button" tabindex="0" aria-label="<?php echo __('Publish');?>" title="<?php echo __('Publish');?>" id="PromptYesButton" class="btn btn-primary" onClick="submitPublish()"><?php echo __('Yes');?></span>
<button role="button" tabindex="0" aria-label="<?= $buttonTitle ?>" title="<?= $buttonTitle ?>" id="PromptYesButton" class="btn btn-primary"><?= __('Yes') ?></button>
</td>
<td style="width:540px;">
</td>
<td style="vertical-align:top;">
<span role="button" tabindex="0" aria-label="<?php echo __('Cancel');?>" title="<?php echo __('Cancel');?>" class="btn btn-inverse" id="PromptNoButton" onClick="cancelPrompt();"><?php echo __('No');?></span>
<span role="button" tabindex="0" aria-label="<?= __('Cancel');?>" title="<?= __('Cancel');?>" class="btn btn-inverse" id="PromptNoButton" onclick="cancelPrompt()"><?= __('No');?></span>
</td>
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

View File

@ -17,7 +17,7 @@
<table>
<tr>
<td style="vertical-align:top">
<span role="button" tabindex="0" aria-label="<?php echo __('Toggle correlation');?>" title="<?php echo __('Toggle correlation');?>" id="PromptYesButton" class="btn btn-primary" onClick="submitPublish();"><?php echo __('Yes');?></span>
<button role="button" tabindex="0" aria-label="<?php echo __('Toggle correlation');?>" title="<?php echo __('Toggle correlation');?>" id="PromptYesButton" class="btn btn-primary"><?php echo __('Yes');?></button>
</td>
<td style="width:540px;">
</td>
@ -27,7 +27,5 @@
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

View File

@ -6,7 +6,7 @@
<p class="bold"><?php echo __('Check out the OpenAPI spec of the MISP Automation API <a href="%s">here</a>.', $baseurl . '/servers/openapi');?></p>
<p><?php echo __('Automation functionality is designed to automatically feed other tools and systems with the data in your MISP repository.
To to make this functionality available for automated tools an authentication key is used.');?>
<br /><?php echo __('You can use the <a href="' . $baseurl . '/servers/rest">REST client</a> to test your API queries against your MISP and export the resulting tuned queries as curl or python scripts.');?>
<br /><?php echo __('You can use the <a href="' . $baseurl . '/api/rest">REST client</a> to test your API queries against your MISP and export the resulting tuned queries as curl or python scripts.');?>
<strong><?php echo __('Make sure you keep your API key secret as it gives access to the all of the data that you normally have access to in MISP.');?></strong>
<?php echo __('To view the old MISP automation page, click <a href="' . $baseurl . '/automation/1">here</a>.');?>
</p>

View File

@ -153,6 +153,12 @@
'style' => 'display:none;width:424px;',
'div' => false
));
echo $this->Form->input('searchall', array(
'label' => false,
'class' => 'input-large',
'style' => 'display:none;width:424px;',
'div' => false
));
?>
<span id="addRuleButton" class="btn btn-inverse" style="margin-bottom:10px;display:none;"><?php echo __('Add');?></span>
</div>
@ -167,7 +173,7 @@
<th style="width:10px;border:1px solid #cccccc;border-left:0px;text-align: left;"></th>
</tr>
<?php
$fields = array('published', 'org', 'tag', 'date', 'eventinfo', 'eventid', 'threatlevel', 'analysis', 'distribution', 'sharinggroup', 'attribute', 'hasproposal', 'timestamp', 'publishtimestamp');
$fields = array('published', 'org', 'tag', 'date', 'eventinfo', 'eventid', 'threatlevel', 'analysis', 'distribution', 'sharinggroup', 'attribute', 'hasproposal', 'timestamp', 'publishtimestamp', 'all');
if ($isSiteAdmin) $fields[] = 'email';
foreach ($fields as $k => $field):
?>
@ -242,9 +248,9 @@ var filtering = <?php echo $filtering; ?>;
var operators = ["<?php echo __('OR');?>", "<?php echo __('NOT');?>"];
var allFields = ["published", "tag", "date", "eventinfo", "eventid", "threatlevel", "distribution", "sharinggroup", "analysis", "attribute", "hasproposal", "timestamp", "publishtimestamp"];
var allFields = ["published", "tag", "date", "eventinfo", "eventid", "threatlevel", "distribution", "sharinggroup", "analysis", "attribute", "hasproposal", "timestamp", "publishtimestamp", "all"];
var simpleFilters = ["tag", "eventinfo", "eventid", "threatlevel", "distribution", "sharinggroup", "analysis", "attribute"];
var simpleFilters = ["tag", "eventinfo", "eventid", "threatlevel", "distribution", "sharinggroup", "analysis", "attribute", "all"];
var differentFilters = ["published", "date", "hasproposal", "timestamp", "publishtimestamp"];

View File

@ -1,7 +1,5 @@
<div class="freetext">
<?php
echo $this->Form->create('Attribute', array('id'));
?>
<?= $this->Form->create('Attribute', array('id')); ?>
<fieldset>
<legend><?php echo __('Freetext Import Tool'); ?></legend>
<div class="add_attribute_fields">
@ -9,35 +7,32 @@ echo $this->Form->create('Attribute', array('id'));
<?php
echo $this->Form->hidden('event_id');
echo $this->Form->input('value', array(
'type' => 'textarea',
'error' => array('escape' => false),
'div' => 'input clear',
'class' => 'input-xxlarge',
'label' => false
'type' => 'textarea',
'error' => array('escape' => false),
'div' => 'input clear',
'class' => 'input-xxlarge',
'label' => false
));
?>
<div class="input clear"></div>
</div>
</fieldset>
<p style="color:red;font-weight:bold;display:none;" id="warning-message"><?php echo __('Warning: You are about to share data that is of a classified nature (Attribution / targeting data). Make sure that you are authorised to share this.');?></p>
<div class="overlay_spacing">
<table>
<tr>
<td style="vertical-align:top">
<button id="submitButton" class="btn btn-primary"><?php echo __('Submit');?></button>
</td>
<td style="width:540px;">
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message"></p>
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="cancel_attribute_add"><?php echo __('Cancel');?></span>
</td>
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<div class="overlay_spacing">
<table>
<tr>
<td style="vertical-align:top">
<button id="submitButton" class="btn btn-primary"><?php echo __('Submit');?></button>
</td>
<td style="width:540px;">
<p style="color:red;font-weight:bold;display:none;text-align:center" id="warning-message"></p>
</td>
<td style="vertical-align:top;">
<span class="btn btn-inverse" id="cancel_attribute_add"><?php echo __('Cancel');?></span>
</td>
</tr>
</table>
</div>
<?= $this->Form->end(); ?>
</div>
<script type="text/javascript">
@ -48,4 +43,3 @@ $(function() {
$('#AttributeValue').focus();
});
</script>
<?php echo $this->Js->writeBuffer(); // Write cached scripts

View File

@ -135,6 +135,7 @@
'button' => __('Filter'),
'placeholder' => __('Enter value to search'),
'data' => '',
'searchKey' => 'searcheventinfo',
)
)
);

View File

@ -9,7 +9,6 @@
echo sprintf('<p class="bold red">%s</p>', $missingTldLists);
}
?>
<p></p>
<?php
$instanceDefault = 5;
if (!empty(Configure::read('MISP.default_attribute_distribution'))) {
@ -22,36 +21,36 @@
echo $this->Form->create('Attribute', array('url' => $baseurl . '/events/saveFreeText/' . $event['Event']['id'], 'class' => 'mainForm'));
if ($isSiteAdmin) {
echo $this->Form->input('force', array(
'checked' => false,
'label' => __('Proposals instead of attributes'),
'checked' => false,
'label' => __('Proposals instead of attributes'),
));
}
echo $this->Form->input('JsonObject', array(
'label' => false,
'type' => 'text',
'style' => 'display:none;',
'value' => '',
'label' => false,
'type' => 'text',
'style' => 'display:none;',
'value' => '',
));
echo $this->Form->input('default_comment', array(
'label' => false,
'type' => 'text',
'style' => 'display:none;',
'value' => $importComment,
'label' => false,
'type' => 'text',
'style' => 'display:none;',
'value' => $importComment,
));
echo $this->Form->end();
?>
<table class="table table-striped table-hover table-condensed">
<tr>
<th><?php echo __('Value');?></th>
<th><?php echo __('Similar Attributes');?></th>
<th><?php echo __('Category');?></th>
<th><?php echo __('Type');?></th>
<th><?php echo __('IDS');?><input type="checkbox" id="checkAllIDS" style="margin-top:0;margin-left:.3em"></th>
<th style="text-align:center;"><?php echo __('Disable Correlation');?><input type="checkbox" id="checkAllDC" style="margin-top:0;margin-left:.3em"></th>
<th><?php echo __('Distribution');?></th>
<th><?php echo __('Comment');?></th>
<th><?php echo __('Tags (separated by comma)');?></th>
<th><?php echo __('Actions');?></th>
<th><?php echo __('Value');?></th>
<th><?php echo __('Similar Attributes');?></th>
<th><?php echo __('Category');?></th>
<th><?php echo __('Type');?></th>
<th><?php echo __('IDS');?><input type="checkbox" id="checkAllIDS" style="margin-top:0;margin-left:.3em"></th>
<th style="text-align:center;"><?php echo __('Disable Correlation');?><input type="checkbox" id="checkAllDC" style="margin-top:0;margin-left:.3em"></th>
<th><?php echo __('Distribution');?></th>
<th><?php echo __('Comment');?></th>
<th><?php echo __('Tags (separated by comma)');?></th>
<th><?php echo __('Actions');?></th>
</tr>
<?php
$options = array();
@ -60,31 +59,31 @@
<tr id="row_<?php echo $k; ?>" class="freetext_row">
<?php
echo $this->Form->input('Attribute' . $k . 'Save', array(
'label' => false,
'style' => 'display:none;',
'value' => 1,
'label' => false,
'style' => 'display:none;',
'value' => 1,
));
echo $this->Form->input('Attribute' . $k . 'Data', array(
'label' => false,
'type' => 'hidden',
'value' => isset($item['data']) ? $item['data'] : false,
'label' => false,
'type' => 'hidden',
'value' => isset($item['data']) ? $item['data'] : false,
));
echo $this->Form->input('Attribute' . $k . 'DataIsHandled', array(
'label' => false,
'type' => 'hidden',
'value' => isset($item['data_is_handled']) ? h($item['data_is_handled']) : false,
'label' => false,
'type' => 'hidden',
'value' => isset($item['data_is_handled']) ? h($item['data_is_handled']) : false,
));
?>
<td>
<?php
echo $this->Form->input('Attribute' . $k . 'Value', array(
'label' => false,
'value' => $item['value'],
'style' => 'padding:0px;height:20px;margin-bottom:0px;width:90%;min-width:400px;',
'div' => false
'label' => false,
'value' => $item['value'],
'style' => 'padding:0px;height:20px;margin-bottom:0px;width:90%;min-width:400px;',
'div' => false
));
?>
<input type="hidden" id="<?php echo 'Attribute' . $k . 'Save'; ?>" value=1 >
<input type="hidden" id="<?php echo 'Attribute' . $k . 'Save'; ?>" value="1">
</td>
<td class="shortish">
<?php
@ -129,8 +128,8 @@
if (isset($item['categories']) && !in_array($category, $item['categories'])) {
continue;
}
echo '<option value="' . $category . '" ';
if ($category == $default) echo 'selected="selected"';
echo '<option';
if ($category == $default) echo ' selected="selected"';
echo '>' . $category . '</option>';
}
?>
@ -140,33 +139,35 @@
<?php
$divVisibility = '';
$selectVisibility = '';
if (count($item['types']) == 1) {
if (count($item['types']) === 1) {
$selectVisibility = 'display:none;';
} else {
$divVisibility = 'style="display:none;"';
if (!in_array(array_keys($item['types']), $options)) $options[] = array_values($item['types']);
if (!in_array($item['types'], $options)) {
$options[] = $item['types'];
}
}
?>
<div id = "<?php echo 'Attribute' . $k . 'TypeStatic'; ?>" <?php echo $divVisibility; ?> ><?php echo h($item['default_type']); ?></div>
<select id = "<?php echo 'Attribute' . $k . 'Type'; ?>" class='typeToggle' style='padding:0px;height:20px;margin-bottom:0px;<?php echo $selectVisibility; ?>'>
<div id="<?php echo 'Attribute' . $k . 'TypeStatic'; ?>" <?php echo $divVisibility; ?> ><?php echo h($item['default_type']); ?></div>
<select id="<?php echo 'Attribute' . $k . 'Type'; ?>" class='typeToggle' style='padding:0px;height:20px;margin-bottom:0px;<?php echo $selectVisibility; ?>'>
<?php
if (!empty($item['types'])) {
foreach ($item['types'] as $type) {
echo '<option value="' . h($type) . '" ';
echo ($type == $item['default_type'] ? 'selected="selected"' : '') . '>' . h($type) . '</option>';
echo '<option';
echo ($type === $item['default_type'] ? ' selected="selected"' : '') . '>' . h($type) . '</option>';
}
}
?>
</select>
</td>
<td class="short" style="width:40px;text-align:center;">
<input type="checkbox" id="<?php echo 'Attribute' . $k . 'To_ids'; ?>" <?php if ($item['to_ids']) echo 'checked'; ?> class="idsCheckbox" />
<input type="checkbox" id="<?php echo 'Attribute' . $k . 'To_ids'; ?>" <?php if ($item['to_ids']) echo 'checked'; ?> class="idsCheckbox">
</td>
<td class="short" style="width:40px;text-align:center;">
<input type="checkbox" id="<?php echo 'Attribute' . $k . 'Disable_correlation'; ?>" <?php if (isset($item['disable_correlation']) && $item['disable_correlation']) echo 'checked'; ?> class="dcCheckbox" />
<input type="checkbox" id="<?php echo 'Attribute' . $k . 'Disable_correlation'; ?>" <?php if (!empty($item['disable_correlation'])) echo 'checked'; ?> class="dcCheckbox">
</td>
<td class="short" style="width:40px;text-align:center;">
<select id = "<?php echo 'Attribute' . $k . 'Distribution'; ?>" class='distributionToggle' style='padding:0px;height:20px;margin-bottom:0px;'>
<select id="<?php echo 'Attribute' . $k . 'Distribution'; ?>" class='distributionToggle' style='padding:0px;height:20px;margin-bottom:0px;'>
<?php
foreach ($distributions as $distKey => $distValue) {
$default = isset($item['distribution']) ? $item['distribution'] : $instanceDefault;
@ -176,7 +177,7 @@
?>
</select>
<div style="display:none;">
<select id = "<?php echo 'Attribute' . $k . 'SharingGroupId'; ?>" class='sgToggle' style='padding:0px;height:20px;margin-top:3px;margin-bottom:0px;'>
<select id="<?php echo 'Attribute' . $k . 'SharingGroupId'; ?>" class='sgToggle' style='padding:0px;height:20px;margin-top:3px;margin-bottom:0px;'>
<?php
foreach ($sgs as $sgKey => $sgValue) {
echo '<option value="' . h($sgKey) . '">' . h($sgValue) . '</option>';
@ -186,13 +187,13 @@
</div>
</td>
<td class="short">
<input type="text" class="freetextCommentField" id="<?php echo 'Attribute' . $k . 'Comment'; ?>" style="padding:0px;height:20px;margin-bottom:0px;" placeholder="<?php echo h($importComment); ?>" <?php if (isset($item['comment']) && $item['comment'] !== false) echo 'value="' . h($item['comment']) . '"'?>/>
<input type="text" class="freetextCommentField" id="<?php echo 'Attribute' . $k . 'Comment'; ?>" style="padding:0px;height:20px;margin-bottom:0px;" placeholder="<?php echo h($importComment); ?>" <?php if (isset($item['comment']) && $item['comment'] !== false) echo 'value="' . h($item['comment']) . '"'?>>
</td>
<td class="short">
<input type="text" class="freetextTagField" id="<?php echo 'Attribute' . $k . 'Tags'; ?>" style="padding:0px;height:20px;margin-bottom:0px;"<?php if (isset($item['tags']) && $item['tags'] !== false) echo 'value="' . h(implode(",",$item['tags'])) . '"'?>/>
<input type="text" class="freetextTagField" id="<?php echo 'Attribute' . $k . 'Tags'; ?>" style="padding:0px;height:20px;margin-bottom:0px;"<?php if (isset($item['tags']) && $item['tags'] !== false) echo 'value="' . h(implode(",",$item['tags'])) . '"'?>>
</td>
<td class="action short">
<span class="fa fa-times useCursorPointer" title="<?php echo __('Remove resolved attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Remove resolved attribute');?>" onClick="freetextRemoveRow('<?php echo $k; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
<span class="fa fa-times useCursorPointer" title="<?php echo __('Remove resolved attribute');?>" role="button" tabindex="0" aria-label="<?php echo __('Remove resolved attribute');?>" onclick="freetextRemoveRow('<?php echo $k; ?>', '<?php echo $event['Event']['id']; ?>');"></span>
</td>
</tr>
<?php
@ -209,7 +210,7 @@
?>
</table>
<span>
<button class="btn btn-primary" style="float:left;" onClick="freetextImportResultsSubmit('<?php echo h($event['Event']['id']); ?>', '<?php echo count($resultArray); ?>');"><?php echo __('Submit %s', $scope);?></button>
<button class="btn btn-primary" style="float:left;" onclick="freetextImportResultsSubmit('<?php echo h($event['Event']['id']); ?>', <?= count($resultArray) ?>);"><?php echo __('Submit %s', $scope);?></button>
<span style="float:right">
<?php
if (!empty($optionsRearranged)):
@ -229,7 +230,7 @@
$keys = array_keys($optionsRearranged);
foreach ($optionsRearranged[$keys[0]] as $toElement):
?>
<option value="<?php echo $toElement; ?>"><?php echo $toElement; ?></option>
<option><?php echo $toElement; ?></option>
<?php
endforeach;
?>
@ -244,7 +245,7 @@
<script>
var options = <?php echo json_encode($optionsRearranged);?>;
var typeCategoryMapping = <?php echo json_encode($typeCategoryMapping); ?>;
$(document).ready(function() {
$(function() {
popoverStartup();
$('.typeToggle').on('change', function() {
var currentId = $(this).attr('id');
@ -266,9 +267,10 @@
}
}
*/
$('#' + currentId).empty();
var $categorySelect = $('#' + currentId);
$categorySelect.empty();
for (var category in currentOptions) {
$('#' + currentId).append($("<option></option>").attr("value", category).text(category));
$categorySelect.append(new Option(category, category));
}
});
<?php
@ -276,16 +278,15 @@
?>
$('#changeFrom').change(function(){
changeFreetextImportFrom();
});
$('#changeFrom').trigger('change');
}).trigger('change');
<?php
endif;
?>
$('#checkAllIDS').change(function() {
$('.idsCheckbox').prop('checked', $('#checkAllIDS').is(':checked'));
$('.idsCheckbox').prop('checked', $(this).is(':checked'));
});
$('#checkAllDC').change(function() {
$('.dcCheckbox').prop('checked', $('#checkAllDC').is(':checked'));
$('.dcCheckbox').prop('checked', $(this).is(':checked'));
});
$('.distributionToggle').change(function() {
if ($(this).val() == 4) {
@ -296,6 +297,4 @@
});
});
</script>
<?php
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'freetextResults'));
?>
<?= $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'freetextResults'));

View File

@ -1,16 +1,12 @@
<?php
$mayModify = (($isAclModify && $event['Event']['user_id'] == $me['id'] && $event['Orgc']['id'] == $me['org_id']) || ($isAclModifyOrg && $event['Orgc']['id'] == $me['org_id']));
$mayPublish = ($isAclPublish && $event['Orgc']['id'] == $me['org_id']);
$menuData = array_merge($menuData, ['mayPublish' => $mayPublish, 'mayModify' => $mayModify]);
$scripts = ['doT', 'extendext', 'moment.min', 'query-builder', 'network-distribution-graph'];
echo $this->element('genericElements/assetLoader', array(
echo $this->element('genericElements/assetLoader', [
'css' => ['query-builder.default', 'attack_matrix'],
'js' => ['doT', 'extendext', 'moment.min', 'query-builder', 'network-distribution-graph']
));
'js' => ['doT', 'extendext', 'moment.min', 'query-builder', 'network-distribution-graph', 'd3', 'd3.custom'],
]);
echo $this->element(
'genericElements/SingleViews/single_view',
[
'title' => ($extended ? '[' . __('Extended view') . '] ' : '') . h(nl2br($event['Event']['info'])),
'title' => ($extended ? '[' . __('Extended view') . '] ' : '') . h(nl2br($event['Event']['info'], false)),
'data' => $event,
'fields' => [
[
@ -182,7 +178,7 @@
],
[
'key' => __('#Attributes'),
'raw' => $attribute_count . __n(' (%s Object)', ' (%s Objects)', $object_count, h($object_count))
'raw' => __n('%s (%s Object)', '%s (%s Objects)', $object_count, $attribute_count, h($object_count))
],
[
'key' => __('First recorded change'),
@ -195,7 +191,7 @@
[
'key' => __('Modification map'),
'type' => 'element',
'element' => 'sparkline',
'element' => 'sparkline_new',
'element_params' => [
'scope' => 'modification',
'id' => $event['Event']['id'],
@ -231,7 +227,7 @@
[
'key' => __('Activity'),
'type' => 'element',
'element' => 'sparkline',
'element' => 'sparkline_new',
'element_params' => [
'scope' => 'event',
'id' => $event['Event']['id'],

View File

@ -8,7 +8,7 @@
<table>
<tr>
<td style="vertical-align:top">
<span role="button" tabindex="0" aria-label="Publish" title="Publish" id="PromptYesButton" class="btn btn-primary" onClick="submitPublish()">Yes</span>
<button role="button" tabindex="0" aria-label="Publish" title="Publish" id="PromptYesButton" class="btn btn-primary">Yes</button>
</td>
<td style="width:540px;">
</td>
@ -18,7 +18,5 @@
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

View File

@ -22,7 +22,7 @@
<table>
<tr>
<td style="vertical-align:top">
<span role="button" tabindex="0" aria-label="<?php echo __('Publish');?>" title="<?php echo __('Publish');?>" id="PromptYesButton" class="btn btn-primary" onClick="submitPublish()"><?php echo __('Yes');?></span>
<button role="button" tabindex="0" aria-label="<?php echo __('Publish');?>" title="<?php echo __('Publish');?>" id="PromptYesButton" class="btn btn-primary"><?php echo __('Yes');?></button>
</td>
<td style="width:540px;">
</td>
@ -32,7 +32,5 @@
</tr>
</table>
</div>
<?php
echo $this->Form->end();
?>
<?= $this->Form->end(); ?>
</div>

Some files were not shown because too many files have changed in this diff Show More