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

pull/4370/head
iglocska 2019-03-26 07:59:35 +01:00
commit a90eaec445
184 changed files with 71830 additions and 32659 deletions

1
.gitignore vendored
View File

@ -72,6 +72,7 @@ tools/mkdocs
/app/Config/database.php
/app/Config/core.php
/app/Config/config.php
/app/Console/Command/training.json
/app/Lib/cakephp
/app/webroot/gpg.asc
/app/tmp/logs

View File

@ -16,11 +16,23 @@
# 0/ Quick MISP Instance on Debian Based Linux - Status |
#-------------------------------------------------------|
#
# 20190208: Kali Linux tested and working.
# 20190302: Ubuntu 18.04.2 tested and working. -- sCl
# 20190208: Kali Linux tested and working. -- sCl
#
#
#-------------------------------------------------------------------------------------------------|
# 1/ For other Debian based Linux distributions, download script and run as **unprivileged** user |
#-------------------------------------------------------------------------------------------------|
#
# The following installs only MISP-core:
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c
#
# This will install MISP Core and misp-modules (recommended)
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c -M
#
#
#-------------------------------------------------------|
# 1/ For Kali, download and run Installer Script |
# 2/ For Kali, download and run Installer Script |
#-------------------------------------------------------|
#
# To install MISP on Kali copy paste the following to your r00t shell:
@ -29,13 +41,6 @@
# The script is tested on a plain vanilla Kali Linux Boot CD and installs quite a few dependencies.
#
#
#---------------------------------------------------------------------------------------------|
# 2/ For other Debian based Linux distributions, download script and run as unprivileged user |
#---------------------------------------------------------------------------------------------|
#
# $ wget -O ~/INSTALL.debian.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh && bash ~/INSTALL.debian.sh -C
#
#
#----------------------------------------------------------|
# 3/ The following script has been partially autogenerated |
#----------------------------------------------------------|
@ -406,25 +411,14 @@ checkUsrLocalSrc () {
else
# TODO: The below might be shorter, more elegant and more modern
#[[ -n $KALI ]] || [[ -n $UNATTENDED ]] && echo "Just do it"
if [ "$KALI" == "1" -o "$UNATTENDED" == "1" ]; then
ANSWER="y"
else
space
echo "/usr/local/src need to be writeable by $MISP_USER for misp-modules, viper etc."
echo -n "Permission to fix? (y/n) "
read ANSWER
ANSWER=$(echo $ANSWER |tr [A-Z] [a-z])
space
fi
if [ "$ANSWER" == "y" ]; then
sudo chmod 2775 /usr/local/src
sudo chown root:staff /usr/local/src
fi
sudo chmod 2775 /usr/local/src
sudo chown root:staff /usr/local/src
fi
else
echo "/usr/local/src does not exist, creating."
mkdir /usr/local/src
mkdir -p /usr/local/src
sudo chmod 2775 /usr/local/src
# FIXME: This might fail on distros with no staff user
sudo chown root:staff /usr/local/src
fi
}
@ -783,7 +777,7 @@ genRCLOCAL () {
# Run PyMISP tests
runTests () {
sudo sed -i -E "s/url\ =\ (.*)/url\ =\ 'https:\/\/misp.local'/g" $PATH_TO_MISP/PyMISP/tests/testlive_comprehensive.py
sudo sed -i -E "s~url\ =\ (.*)~url\ =\ '${MISP_BASEURL}'~g" $PATH_TO_MISP/PyMISP/tests/testlive_comprehensive.py
sudo sed -i -E "s/key\ =\ (.*)/key\ =\ '${AUTH_KEY}'/g" $PATH_TO_MISP/PyMISP/tests/testlive_comprehensive.py
sudo chown -R $WWW_USER:$WWW_USER $PATH_TO_MISP/PyMISP/
@ -1345,6 +1339,7 @@ mispmodules () {
##sudo sed -i -e '$i \sudo -u www-data /var/www/MISP/venv/bin/misp-modules -l 127.0.0.1 -s > /tmp/misp-modules_rc.local.log &\n' /etc/rc.local
cd /usr/local/src/
## TODO: checkUsrLocalSrc in main doc
debug "Cloning misp-modules"
$SUDO_USER git clone https://github.com/MISP/misp-modules.git
cd misp-modules
# some misp-modules dependencies
@ -1490,17 +1485,20 @@ dashboardCAKE () {
mail2misp () {
debug "Installing Mail2${LBLUE}MISP${NC}"
cd /usr/local/src/
sudo apt-get install cmake libcaca-dev -y
sudo apt-get install cmake libcaca-dev liblua5.3-dev -y
$SUDO_USER git clone https://github.com/MISP/mail_to_misp.git
$SUDO_USER git clone git://github.com/stricaud/faup.git faup
sudo chown -R ${MISP_USER}:${MISP_USER} faup mail_to_misp
cd faup
# TODO Check permissions
##$SUDO mkdir -p build
$SUDO_USER git clone git://github.com/stricaud/gtcaca.git gtcaca
sudo chown -R ${MISP_USER}:${MISP_USER} faup mail_to_misp gtcaca
cd gtcaca
$SUDO_USER mkdir -p build
cd build
$SUDO_USER cmake .. && $SUDO_USER make
sudo make install
cd ../../faup
$SUDO_USER mkdir -p build
cd build
$SUDO_USER cmake .. && $SUDO_USER make
##$SUDO cmake .. && $SUDO make
sudo make install
sudo ldconfig
cd ../../mail_to_misp

View File

@ -16,11 +16,23 @@
# 0/ Quick MISP Instance on Debian Based Linux - Status |
#-------------------------------------------------------|
#
# 20190208: Kali Linux tested and working.
# 20190302: Ubuntu 18.04.2 tested and working. -- sCl
# 20190208: Kali Linux tested and working. -- sCl
#
#
#-------------------------------------------------------------------------------------------------|
# 1/ For other Debian based Linux distributions, download script and run as **unprivileged** user |
#-------------------------------------------------------------------------------------------------|
#
# The following installs only MISP-core:
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c
#
# This will install MISP Core and misp-modules (recommended)
# $ curl -fsSL https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh | bash -s -- -c -M
#
#
#-------------------------------------------------------|
# 1/ For Kali, download and run Installer Script |
# 2/ For Kali, download and run Installer Script |
#-------------------------------------------------------|
#
# To install MISP on Kali copy paste the following to your r00t shell:
@ -29,13 +41,6 @@
# The script is tested on a plain vanilla Kali Linux Boot CD and installs quite a few dependencies.
#
#
#---------------------------------------------------------------------------------------------|
# 2/ For other Debian based Linux distributions, download script and run as unprivileged user |
#---------------------------------------------------------------------------------------------|
#
# $ wget -O ~/INSTALL.debian.sh https://raw.githubusercontent.com/MISP/MISP/2.4/INSTALL/INSTALL.debian.sh && bash ~/INSTALL.debian.sh -C
#
#
#----------------------------------------------------------|
# 3/ The following script has been partially autogenerated |
#----------------------------------------------------------|

View File

@ -710,6 +710,7 @@ CREATE TABLE IF NOT EXISTS `roles` (
`max_execution_time` VARCHAR(255) COLLATE utf8_bin DEFAULT "",
`restricted_to_site_admin` tinyint(1) NOT NULL DEFAULT 0,
`perm_publish_zmq` tinyint(1) NOT NULL DEFAULT 0,
`perm_publish_kafka` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
@ -1261,23 +1262,23 @@ INSERT INTO `feeds` (`id`, `provider`, `name`, `url`, `distribution`, `default`,
-- 7. Read Only - read
--
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (1, 'admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (2, 'Org Admin', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (3, 'User', NOW(), NOW(), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (4, 'Publisher', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (5, 'Sync user', NOW(), NOW(), 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (6, 'Read Only', NOW(), NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
INSERT INTO `roles` (`id`, `name`, `created`, `modified`, `perm_add`, `perm_modify`, `perm_modify_org`, `perm_publish`, `perm_publish_zmq`, `perm_publish_kafka`, `perm_sync`, `perm_admin`, `perm_audit`, `perm_full`, `perm_auth`, `perm_regexp_access`, `perm_tagger`, `perm_site_admin`, `perm_template`, `perm_sharing_group`, `perm_tag_editor`, `perm_delegate`, `perm_sighting`, `perm_object_template`, `default_role`)
VALUES (6, 'Read Only', NOW(), NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
-- --------------------------------------------------------

View File

@ -309,13 +309,13 @@ COPY public.regexp (id, regexp, replacement, type) FROM stdin;
-- Data for Name: roles; Type: TABLE DATA; Schema: public; Owner: -
--
COPY public.roles (id, name, created, modified, perm_add, perm_modify, perm_modify_org, perm_publish, perm_delegate, perm_sync, perm_admin, perm_audit, perm_full, perm_auth, perm_site_admin, perm_regexp_access, perm_tagger, perm_template, perm_sharing_group, perm_tag_editor, perm_sighting, perm_object_template, default_role, memory_limit, max_execution_time, restricted_to_site_admin, perm_publish_zmq) FROM stdin;
1 admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t t t t t t t t t t t t t f f t
2 Org Admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f t t f t f f t t t t t f f f t
3 User 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t f f f f f f t f f f f f f t f t f f
4 Publisher 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f f f f t f f f f f f t f f f t
5 Sync user 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t f f f t f f f f t f t f f f t
6 Read Only 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 f f f f f f f f f t f f f f f f f f f f f
COPY public.roles (id, name, created, modified, perm_add, perm_modify, perm_modify_org, perm_publish, perm_delegate, perm_sync, perm_admin, perm_audit, perm_full, perm_auth, perm_site_admin, perm_regexp_access, perm_tagger, perm_template, perm_sharing_group, perm_tag_editor, perm_sighting, perm_object_template, default_role, memory_limit, max_execution_time, restricted_to_site_admin, perm_publish_zmq, perm_publish_kafka) FROM stdin;
1 admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t t t t t t t t t t t t t f f t t
2 Org Admin 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f t t f t f f t t t t t f f f t t
3 User 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t f f f f f f t f f f f f f t f t f f f
4 Publisher 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t f f f f t f f f f f f t f f f t t
5 Sync user 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 t t t t t t f f f t f f f f t f t f f f t t
6 Read Only 2018-11-27 06:22:00+00 2018-11-27 06:22:00+00 f f f f f f f f f t f f f f f f f f f f f f
\.

View File

@ -1134,7 +1134,8 @@ CREATE TABLE public.roles (
memory_limit character varying(255) DEFAULT ''::character varying,
max_execution_time character varying(255) DEFAULT ''::character varying,
restricted_to_site_admin boolean DEFAULT false NOT NULL,
perm_publish_zmq boolean DEFAULT false NOT NULL
perm_publish_zmq boolean DEFAULT false NOT NULL,
perm_publish_kafka boolean DEFAULT false NOT NULL
);

View File

@ -237,3 +237,8 @@ Optional features
-------------------
# MISP has a new pub/sub feature, using ZeroMQ. To enable it, simply run the following command
pip install pyzmq
# MISP has a feature for publishing events to Kafka. To enable it, simply run the following commands
apt-get install librdkafka-dev php-dev
pecl install rdkafka
find /etc -name php.ini | while read f; do echo 'extension=rdkafka.so' | tee -a "$f"; done

View File

@ -253,3 +253,8 @@ Optional features
pip install pyzmq
# ZeroMQ depends on the Python client for Redis
pip install redis
# MISP has a feature for publishing events to Kafka. To enable it, simply run the following commands
apt-get install librdkafka-dev php-dev
pecl install rdkafka
find /etc -name php.ini | while read f; do echo 'extension=rdkafka.so' | tee -a "$f"; done

View File

@ -270,6 +270,11 @@ sudo pip install pyzmq
# ZeroMQ depends on the Python client for Redis
sudo pip install redis
# MISP has a feature for publishing events to Kafka. To enable it, simply run the following commands
apt-get install librdkafka-dev php-dev
pecl install rdkafka
find /etc -name php.ini | while read f; do echo 'extension=rdkafka.so' | tee -a "$f"; done
# For the experimental ssdeep correlations, run the following installation:
# installing ssdeep
wget http://downloads.sourceforge.net/project/ssdeep/ssdeep-2.13/ssdeep-2.13.tar.gz

2
PyMISP

@ -1 +1 @@
Subproject commit c35a2aea5544f323282b4737ce51b8fa4881b002
Subproject commit c888af177f88af653ad395924a3b840ca22f0af4

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":102}
{"major":2, "minor":4, "hotfix":104}

View File

@ -159,6 +159,7 @@ $config = array(
//
'ldapDefaultOrg' => '1', // uses 1st local org in MISP if undefined,
'ldapAllowReferrals' => true, // allow or disallow chasing LDAP referrals
//'ldapEmailField' => array('emailAddress, 'mail'), // Optional : fields from which the email address should be retrieved. Default to 'mail' only. If more than one field is set (e.g. 'emailAddress' and 'mail' in this example), only the first one will be used.
),
*/
);

View File

@ -0,0 +1,585 @@
<?php
/*
* Reset a password
*
* arg0 = email
* arg1 = new password
*/
class TrainingShell extends AppShell {
public $uses = array('User', 'Organisation', 'Server');
private $__currentUrl = false;
private $__currentAuthKey = false;
private $__simulate = false;
private $__config = false;
private $__report = array();
private $__verbose = false;
private $__interactive = false;
public function simulate()
{
$this->__simulate = true;
$this->setup();
}
public function setup()
{
$this->__verbose = !empty($this->params['verbose']);
$this->__interactive = !empty($this->params['interactive']);
$this->__config = file_get_contents(APP . 'Console/Command/training.json');
if (empty($this->__config)) {
echo 'No config file found. Make sure that training.json exists and is configured.';
die();
}
$this->__config = json_decode($this->__config, true);
$this->__report = array();
for ($i = $this->__config['ID_start']; $i < ($this->__config['ID_start'] + $this->__config['number_of_misps_to_configure']); $i++) {
$id = $i;
if ($this->__config['ID_zero_out']) {
if ($id < 10) {
$id = '0' . $id;
}
}
$this->__currentUrl = str_replace('$ID', $id, $this->__config['server_blueprint']);
if ($this->__interactive) {
$question = sprintf('Configure instance at %s?', $this->__currentUrl);
$input = $this->__user_input($question, array('y', 'n'));
if ($input === 'n') {
$this->__printReport('Stopping execution. Data created so far:' . PHP_EOL . PHP_EOL);
die();
}
}
if ($this->__verbose) {
echo 'INFO - Instance to configure' . $this->__currentUrl . PHP_EOL;
}
$org = $this->__createOrgFromBlueprint($id);
$this->__setSetting('MISP.host_org_id', $org['Organisation']['remote_org_id'], $id, $org['Organisation']['name']);
$this->__report['servers'][$this->__currentUrl]['host_org_id'] = $org['Organisation']['remote_org_id'];
$this->__report['remote_orgs'][] = array('id' => $org['Organisation']['remote_org_id'], 'name' => $org['Organisation']['name']);
$role_id = $this->__createRole($this->__config['role_blueprint']);
$this->__report['servers'][$this->__currentUrl]['training_role_id'] = $role_id;
$sync_user = $this->__createSyncUserLocally($org['Organisation']['remote_org_id'], $org['Organisation']['name']);
$this->__report['users'][] = $sync_user;
$local_host_org = $this->__getLocalHostOrgId();
$hub_org_id_on_remote = $this->__createOrg($local_host_org);
$external_baseurl = empty(Configure::read('MISP.external_baseurl')) ? Configure::read('MISP.baseurl') : Configure::read('MISP.external_baseurl');
$this->__report['servers'][$this->__currentUrl]['sync_connections'][] = $this->__addSyncConnection($external_baseurl, 'Exercise hub', $local_host_org, $hub_org_id_on_remote, $sync_user);
$this->__report['servers'][$this->__currentUrl]['users'] = $this->__createUsers($org['Organisation']['remote_org_id'], $role_id, $org['Organisation']['name'], $id);
if (!empty($this->__config['create_sync_both_ways'])) {
$this->__createReverseSyncConnection($org['Organisation']['id'], $org['Organisation']['name'], $local_host_org);
}
if (!empty($this->__config['create_admin_user'])) {
$this->__report['servers'][$this->__currentUrl['users']][] = $this->__addAdminUserRemotely($i, $org['Organisation']['name'], $org['Organisation']['remote_org_id']);
}
if (!empty($this->__config['settings'])) {
foreach ($this->__config['settings'] as $key => $value)
$this->__setSetting($key, $value, $id, $org['Organisation']['name']);
}
if ($this->__config['reset_admin_credentials']) {
$this->__report['servers'][$this->__currentUrl]['management_account'] = $this->__reset_admin_credentials($this->__report);
}
}
$this->__printReport('Setup complete. Please find the modifications below:' . PHP_EOL . PHP_EOL);
}
private function __createOrgFromBlueprint($id)
{
$org = str_replace('$ID', $id, $this->__config['org_blueprint']);
$org_id = $this->Organisation->createOrgFromName($org, 1, true);
$org_data = $this->Organisation->find('first', array(
'recursive' => -1,
'fields' => array('name', 'uuid', 'local'),
'conditions' => array('Organisation.id' => $org_id)
));
$org_data['Organisation']['remote_org_id'] = $this->__createOrg($org_data);
return $org_data;
}
private function __getLocalHostOrgId()
{
$org = $this->Organisation->find('first', array(
'recursive' => -1,
'conditions' => array(
'Organisation.id' => empty(Configure::read('MISP.host_org_id')) ? -1 : Configure::read('MISP.host_org_id')
),
'fields' => array(
'name', 'id', 'uuid'
)
));
if (empty($org)) {
$this->__printReport('Stopping execution, no host_org_id set on the current instance, or the setting points to a non-existing org. Data created so far:' . PHP_EOL . PHP_EOL);
die();
}
return $org;
}
private function __createReverseSyncConnection($remote_org_id_on_local, $org_name, $host_org_id_on_local)
{
$sync_user = $this->__addSyncUserRemotely();
$this->__report['servers'][$this->__currentUrl]['users'][] = $sync_user;
$sync_server = $this->__addSyncConnectionLocally($this->__currentUrl, $org_name . '_misp', $remote_org_id_on_local, $sync_user, $host_org_id_on_local);
if ($sync_server) {
$this->__report['sync'][] = $sync_server;
}
}
private function __printReport($message)
{
echo json_encode($this->__report, JSON_PRETTY_PRINT);
$this->__report = '';
return true;
}
private function __findRemoteRoleId($role_name)
{
$options = array(
'url' => $this->__currentUrl . '/roles/index',
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code == 200) {
$roles = json_decode($response->body, true);
foreach ($roles as $role) {
if ($role['Role']['name'] == $role_name) {
return $role['Role']['id'];
}
}
} else {
$this->__responseError($response, $options);
}
return false;
}
private function __getRemoteAdminUser()
{
$options = array(
'url' => $this->__currentUrl . '/users/view/me',
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code == 200) {
return json_decode($response->body, true);
} else {
$this->__responseError($response, $options);
}
return false;
}
private function __addAdminUserRemotely($i, $org, $remote_org_id)
{
$email = $this->__config['user_blueprint'];
$email = str_replace('$ORGNAME', $org, $email);
$email = str_replace('$ID', $i, $email);
$email = 'admin' . substr($email, strpos($email, '@'));
$admin_role_id = $this->__findRemoteRoleId('Admin');
if (!$admin_role_id) {
echo 'Remote instance lacks the required role (Admin).' . PHP_EOL ;
die();
}
$options = array(
'url' => $this->__currentUrl . '/admin/users/index/searchall:' . $email,
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
}
$newKey = $this->User->generateRandomPassword(32);
if (empty(json_decode($response->body, true))) {
$user = array(
'email' => $email,
'password' => $newKey,
'role_id' => $admin_role_id,
'org_id' => $remote_org_id
);
$options = array(
'url' => $this->__currentUrl . '/admin/users/add',
'method' => 'POST',
'body' => $user
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
if (!$this->__simulate) {
$user['authkey'] = $response_data['User']['authkey'];
}
}
} else {
$user = json_decode($response->body, true)[0]['User'];
}
return $user;
}
private function __addSyncUserRemotely()
{
$sync_user_role_id = $this->__findRemoteRoleId('Sync user');
if (!$sync_user_role_id) {
echo 'Remote instance lacks the required role (Sync user).' . PHP_EOL ;
die();
}
$remote_admin = $this->__getRemoteAdminUser();
if (!$remote_admin) {
echo 'Remote instance did not return the admin user\'s information.' . PHP_EOL ;
die();
}
$email = $remote_admin['User']['email'];
$email = 'sync' . substr($email, strpos($email, '@'));
$options = array(
'url' => $this->__currentUrl . '/admin/users/index/searchall:' . $email,
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
}
$newKey = $this->User->generateRandomPassword(32);
if (empty(json_decode($response->body, true))) {
$user = array(
'email' => $email,
'password' => $newKey,
'role_id' => $sync_user_role_id,
'org_id' => $remote_admin['User']['role_id']
);
$options = array(
'url' => $this->__currentUrl . '/admin/users/add',
'method' => 'POST',
'body' => $user
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
if (!$this->__simulate) {
$user['authkey'] = $response_data['User']['authkey'];
}
}
} else {
$user = json_decode($response->body, true)[0]['User'];
}
return $user;
}
private function __addSyncConnectionLocally($baseurl, $org_name, $remote_org_id_on_local, $sync_user)
{
$this->Server->create();
$server = array(
"name" => $org_name,
"url" => $baseurl,
"authkey" => $sync_user['authkey'],
"push" => 1,
"pull" => 1,
"remote_org_id" => $sync_user['org_id'],
"self_signed" => 1,
"org_id" => $host_org_id_on_local
);
$result = $this->Server->save($server);
if (!$result) {
echo sprintf(
'Could not add connection to %s. Reason: %s.' . PHP_EOL,
$baseurl,
json_encode($this->Server->validationErrors)
);
return false;
}
return $server;
}
private function __addSyncConnection($baseurl, $name, $local_host_org, $hub_org_id_on_remote, $sync_user)
{
$server = array(
'name' => $name,
'url' => $baseurl,
'authkey' => $sync_user['User']['authkey'],
'remote_org_id' => $hub_org_id_on_remote,
'push' => 1,
'pull' => 1,
'self_signed' => 1
);
$options = array(
'url' => $this->__currentUrl . '/servers/add',
'method' => 'POST',
'body' => $server
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
return array(
'url' => $response_data['Server']['url'],
'authkey' => $response_data['Server']['authkey']
);
}
}
private function __createSyncUserLocally($remote_org_id, $org)
{
$sync_role = $this->User->Role->find('first', array('recursive' => -1, 'conditions' => array('Role.name' => 'Sync user')));
$sync_role = $sync_role['Role']['id'];
$this->User->create();
$this->User->save(array(
'external_auth_required' => 0,
'external_auth_key' => '',
'server_id' => 0,
'gpgkey' => '',
'certif_public' => '',
'autoalert' => 0,
'contactalert' => 0,
'disabled' => 0,
'newsread' => 0,
'change_pw' => 1,
'authkey' => $this->User->generateAuthKey(),
'termsaccepted' => 0,
'org_id' => $remote_org_id,
'role_id' => $sync_role,
'email' => 'sync_user@' . $org . '.test'
));
$user = $this->User->find('first', array('recursive' => -1, 'conditions' => array('User.email' => 'sync_user@' . $org . '.test')));
return $user;
}
private function __responseError($response, $options)
{
echo sprintf(
"Received a non-200 response (%s). Aborting.\nQueried URL: %s\n Query type: %s\n Request payload: %s\n\n",
$response->code,
$options['url'],
$options['method'],
empty($options['body']) ? '' : json_encode($options['body'], JSON_PRETTY_PRINT)
);
if ($this->__interactive) {
$question = 'The above error can cause the issues to compound if you continue. For example, not creating an organisation that subsequently created users should belong to will fail. Would you like to continue?';
$input = $this->__user_input($question, array('y', 'n'));
if ($input === 'y') {
return true;
}
}
$this->__printReport('Setup failed. Output of what has been created:' . PHP_EOL . PHP_EOL);
die();
}
private function __createUsers($remote_org_id, $role_id, $org, $i)
{
$summary = array();
for ($j = 1; $j < (1 + $this->__config['user_count']); $j++) {
$email = $this->__config['user_blueprint'];
$email = str_replace('$ID', $i, $email);
$email = str_replace('$ORGNAME', $org, $email);
$email = str_replace('$USER_ITERATOR', $j, $email);
$options = array(
'url' => $this->__currentUrl . '/admin/users/index/searchall:' . $email,
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
}
$newKey = $this->User->generateRandomPassword(32);
if (empty(json_decode($response->body, true))) {
$user = array(
'email' => $email,
'password' => $newKey,
'role_id' => $role_id,
'org_id' => $remote_org_id
);
$options = array(
'url' => $this->__currentUrl . '/admin/users/add',
'method' => 'POST',
'body' => $user
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
if ($this->__simulate) {
$summary[] = $user;
} else {
$user['authkey'] = $response_data['User']['authkey'];
$summary[] = $user;
}
}
}
}
return $summary;
}
private function __createRole($blueprint)
{
$blueprint = array('Role' => $blueprint);
$options = array(
'url' => $this->__currentUrl . '/roles/index',
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code == 200) {
$roles = json_decode($response->body, true);
$found = false;
foreach ($roles as $role) {
if ($role['Role']['name'] == $blueprint['Role']['name']) {
return $role['Role']['id'];
}
}
$options = array(
'url' => $this->__currentUrl . '/admin/roles/add',
'method' => 'POST',
'body' => $blueprint
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
return $response_data['Role']['id'];
}
} else {
$this->__responseError($response, $options);
}
}
private function __reset_admin_credentials()
{
$credentials = array(
'authkey' => $this->User->generateAuthKey(),
'password' => $this->User->generateRandomPassword(32)
);
$this->__queryRemoteMISP(array(
'url' => $this->__currentUrl . '/admin/users/edit/1',
'body' => array('User' => array(
'password' => $credentials['password'],
'authkey' => $credentials['authkey']
)),
'method' => 'POST'
));
return $credentials;
}
private function __createOrg($org_data)
{
$options = array(
'url' => $this->__currentUrl . '/organisations/index.json',
'method' => 'GET'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
$response_data = json_decode($response->body, true);
$found = false;
foreach ($response_data as $existingOrg) {
if ($existingOrg['Organisation']['name'] == $org_data['Organisation']['name']) {
return $existingOrg['Organisation']['id'];
}
}
$options = array(
'body' => $org_data,
'url' => $this->__currentUrl . '/admin/organisations/add',
'method' => 'POST'
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
}
return $response_data['Organisation']['id'];
}
}
private function __user_input($question, $valid_input_options)
{
$valid_input = false;
while (!$valid_input) {
echo sprintf(
'%s (%s)' . PHP_EOL,
$question,
implode('/', $valid_input_options)
);
$handle = fopen ("php://stdin","r");
$input = trim(strtolower(fgets($handle)));
if (in_array($input, $valid_input_options)) {
$valid_input = true;
}
}
return $input;
}
private function __setSetting($key, $value, $i, $org)
{
$value = str_replace('$ID', $i, $value);
$value = str_replace('$ORGNAME', $org, $value);
$options = array(
'url' => $this->__currentUrl . '/servers/serverSettingsEdit/' . $key,
'method' => 'POST',
'body' => array('value' => $value)
);
$response = $this->__queryRemoteMISP($options, true);
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
return true;
}
}
private function __queryRemoteMISP($options, $returnFullResponse = false)
{
$params = array();
App::uses('HttpSocket', 'Network/Http');
$params['ssl_allow_self_signed'] = true;
$params['ssl_verify_peer_name'] = false;
$params['ssl_verify_peer'] = false;
$HttpSocket = new HttpSocket($params);
$request = array(
'header' => array(
'Authorization' => $this->__config['authkey'],
'Accept' => 'application/json',
'Content-Type' => 'application/json'
)
);
if ($this->__simulate) {
if ($this->__verbose) {
echo 'SIMULATION - query to be executed:' . PHP_EOL . json_encode($options) . PHP_EOL . ' using request object:' . PHP_EOL . json_encode($request) . PHP_EOL . PHP_EOL;
}
$response = new class{};
$response->code = 200;
$response->body = '{"id": 666, "Organisation": {"id": 666}, "User": {"id": 666, "email": "foo"}, "Role": {"id": 666}, "Server": {"url": "https://foo.bar", "authkey": "bla"}}';
return $response;
} else {
if ($this->__verbose) {
echo 'EXEC - query to be executed:' . PHP_EOL . json_encode($options) . PHP_EOL . ' using request object:' . PHP_EOL . json_encode($request) . PHP_EOL . PHP_EOL;
}
if ($options['method'] === 'POST') {
$response = $HttpSocket->post($options['url'], json_encode($options['body']), $request);
} else {
$response = $HttpSocket->get($options['url'], '', $request);
}
if ($returnFullResponse) {
return $response;
}
if ($response->code != 200) {
$this->__responseError($response, $options);
} else {
return json_decode($response->body, true);
}
}
}
public function getOptionParser()
{
$parser = parent::getOptionParser();
$parser->addOption('verbose', array(
'short' => 'v',
'help' => __('verbose mode'),
'boolean' => 1
))->addOption('interactive', array(
'short' => 'i',
'help' => __('interactive mode'),
'boolean' => 1
));
return $parser;
}
}

View File

@ -0,0 +1,43 @@
{
"ID_start": 1,
"ID_zero_out": 0,
"number_of_misps_to_configure": 5,
"reset_admin_credentials": 1,
"create_sync_both_ways": 0,
"create_admin_user": 0,
"settings": {
},
"authkey": "111111111111111111111111111111111",
"server_blueprint": "https://my_remote_misp$ID",
"user_blueprint": "user$USER_ITERATOR@user.$ORGNAME.test",
"user_count": 2,
"org_blueprint": "org$ID",
"role_blueprint": {
"name": "training_participant",
"perm_add": true,
"perm_modify": true,
"perm_modify_org": true,
"perm_publish": true,
"perm_delegate": true,
"perm_sync": true,
"perm_admin": true,
"perm_audit": true,
"perm_auth": true,
"perm_site_admin": false,
"perm_regexp_access": true,
"perm_tagger": true,
"perm_template": true,
"perm_sharing_group": true,
"perm_tag_editor": true,
"perm_sighting": true,
"perm_object_template": true,
"default_role": false,
"memory_limit": "",
"max_execution_time": "",
"restricted_to_site_admin": false,
"perm_publish_zmq": true,
"permission": "3",
"permission_description": "training_participant"
}
}

View File

@ -1,34 +1,57 @@
#!/usr/bin/env bash
# TODO: Improve script to bring workers up that are not.
# TODO: Put some logic inside if many worker PIDs are detected
# Extract base directory where this script is and cd into it
cd "${0%/*}"
# Set to the current webroot owner
WWW_USER=$(ls -l ../cake |awk {'print $3'}|tail -1)
# In most cases the owner of the cake script is also the user as which it should be executed.
if [[ "$USER" != "$WWW_USER" ]]; then
echo "You run this script as $USER and the owner of the cake command is $WWW_USER. This might be an issue."
fi
# Check if run as root
if [ "$EUID" -eq 0 ]; then
if [[ "$EUID" -eq "0" ]]; then
echo "Please DO NOT run the worker script as root"
exit 1
fi
##[[ $(../cake CakeResque.CakeResque stop --all |grep "not permitted" ; echo $?) != 1 ]] && echo "Either you have no permissions or CakeResque is not installed/configured" && exit 1
## FIXME: PIDs seem off by 1
# Check which workers are currently running
WORKERS_PID=$(ps a |grep CakeResque |grep -v grep |cut -f 1 -d\ )
if [[ ! -z $WORKERS_PID ]]; then
for p in $WORKERS_PID; do
WORKER_RUNNING=$(ps $p |grep CakeRes|grep -v grep |grep -o -e "QUEUE=.[a-z]*" |cut -f2 -d\')
#echo "Worker $WORKER_RUNNING with PID $p"
done
# Check if jq is present and enable advanced checks
if [[ "$(jq -V > /dev/null 2> /dev/null; echo $?)" != 0 ]]; then
echo "jq is not installed, disabling advanced checks."
ADVANCED="0"
else
ADVANCED="1"
fi
../cake CakeResque.CakeResque stop --all
../cake CakeResque.CakeResque start --interval 5 --queue default
../cake CakeResque.CakeResque start --interval 5 --queue prio
../cake CakeResque.CakeResque start --interval 5 --queue cache
../cake CakeResque.CakeResque start --interval 5 --queue email
../cake CakeResque.CakeResque startscheduler --interval 5
if [[ "$ADVANCED" == "1" ]]; then
for worker in `echo cache default email prio scheduler`; do
workerStatus=$(../cake Admin getWorkers |tail -n +7 |jq -r ".$worker" |jq -r '.ok')
PIDcount=$(../cake admin getWorkers |tail -n +7 |jq -r ".$worker.workers" |grep pid | wc -l)
echo -n "$worker has $PIDcount PID(s)"
if [[ "$workerStatus" != "true" ]]; then
echo ", trying to restart."
if [[ "$worker" != "scheduler" ]]; then
../cake CakeResque.CakeResque start --interval 5 --queue $worker
else
../cake CakeResque.CakeResque startscheduler --interval 5
fi
else
echo ", up and running."
fi
done
exit 0
else
exit 0
../cake CakeResque.CakeResque stop --all
../cake CakeResque.CakeResque start --interval 5 --queue default
../cake CakeResque.CakeResque start --interval 5 --queue prio
../cake CakeResque.CakeResque start --interval 5 --queue cache
../cake CakeResque.CakeResque start --interval 5 --queue email
../cake CakeResque.CakeResque startscheduler --interval 5
exit 0
fi

22
app/Console/worker/stop.sh Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/env bash
# TODO: Put some logic inside if many worker PIDs are detected
# Extract base directory where this script is and cd into it
cd "${0%/*}"
# Set to the current webroot owner
WWW_USER=$(ls -l ../cake |awk {'print $3'}|tail -1)
# In most cases the owner of the cake script is also the user as which it should be executed.
if [[ "$USER" != "$WWW_USER" ]]; then
echo "You run this script as $USER and the owner of the cake command is $WWW_USER. This might be an issue."
fi
# Check if run as root
if [[ "$EUID" -eq "0" ]]; then
echo "Please DO NOT run the worker script as root"
exit 1
fi
../cake CakeResque.CakeResque stop --all

View File

@ -46,8 +46,8 @@ class AppController extends Controller
public $helpers = array('Utility', 'OrgImg');
private $__queryVersion = '60';
public $pyMispVersion = '2.4.102';
private $__queryVersion = '63';
public $pyMispVersion = '2.4.103';
public $phpmin = '7.0';
public $phprec = '7.2';
@ -442,6 +442,7 @@ class AppController extends Controller
$this->set('isAclSharingGroup', $role['perm_sharing_group']);
$this->set('isAclSighting', isset($role['perm_sighting']) ? $role['perm_sighting'] : false);
$this->set('isAclZmq', isset($role['perm_publish_zmq']) ? $role['perm_publish_zmq'] : false);
$this->set('isAclKafka', isset($role['perm_publish_kafka']) ? $role['perm_publish_kafka'] : false);
$this->userRole = $role;
} else {
$this->set('me', false);

View File

@ -254,6 +254,10 @@ class AttributesController extends AppController
}
foreach ($attributes as $k => $attribute) {
if (empty($attribute['blocked'])) {
if (!empty($attribute['encrypt'])) {
$attribute = $this->Attribute->onDemandEncrypt($attribute);
}
$attributes[$k] = $attribute;
$this->Attribute->set($attribute);
$result = $this->Attribute->validates();
if (!$result) {
@ -1171,7 +1175,7 @@ class AttributesController extends AppController
throw new NotFoundException('Invalid attribute');
}
if ($this->_isRest()) {
$conditions = array('conditions' => array('Attribute.id' => $id), 'withAttachments' => true);
$conditions = array('conditions' => array('Attribute.id' => $id), 'withAttachments' => true, 'flatten' => true);
$conditions['includeAllTags'] = false;
$conditions['includeAttributeUuid'] = true;
$attribute = $this->Attribute->fetchAttributes($this->Auth->user(), $conditions);
@ -2890,23 +2894,30 @@ class AttributesController extends AppController
foreach ($modules['modules'] as $temp) {
if ($temp['name'] == $type) {
$found = true;
$format = (isset($temp['mispattributes']['format']) ? $temp['mispattributes']['format'] : 'simplified');
if (isset($temp['meta']['config'])) {
foreach ($temp['meta']['config'] as $conf) {
$options[$conf] = Configure::read('Plugin.Enrichment_' . $type . '_' . $conf);
}
}
break;
}
}
if (!$found) {
throw new MethodNotAllowedException(__('No valid enrichment options found for this attribute.'));
}
$data = array('module' => $type, $attribute[0]['Attribute']['type'] => $attribute[0]['Attribute']['value']);
$data = array('module' => $type);
if ($persistent) {
$data['persistent'] = 1;
}
if (!empty($options)) {
$data['config'] = $options;
}
if ($format == 'misp_standard') {
$data['attribute'] = $attribute[0]['Attribute'];
} else {
$data[$attribute[0]['Attribute']['type']] = $attribute[0]['Attribute']['value'];
}
$data = json_encode($data);
$result = $this->Module->queryModuleServer('/query', $data, true);
if ($result) {
@ -2988,10 +2999,6 @@ class AttributesController extends AppController
public function addTag($id = false, $tag_id = false)
{
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that. Only POST requests are accepted.')), 'status' => 200, 'type' => 'json'));
}
$rearrangeRules = array(
'request' => false,
'Attribute' => false,
@ -3007,140 +3014,148 @@ class AttributesController extends AppController
if ($id === 'selected') {
$idList = json_decode($this->request->data['attribute_ids'], true);
}
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
if (!is_numeric($tag_id)) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
// try to parse json array
$tag_ids = json_decode($tag_id);
if ($tag_ids !== null) { // can decode json
$tag_id_list = array();
foreach ($tag_ids as $tag_id) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_id_list[] = $tag_id;
}
}
} else {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
}
if (!isset($idList)) {
$idList = array($id);
}
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
$success = 0;
$fails = 0;
foreach ($idList as $id) {
$this->Attribute->id = $id;
if (!$this->Attribute->exists()) {
throw new NotFoundException(__('Invalid attribute'));
}
$this->Attribute->read();
if (!$this->_isSiteAdmin() && $this->Attribute->data['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
$fails++;
continue;
}
if ($this->Attribute->data['Attribute']['deleted']) {
throw new NotFoundException(__('Invalid attribute'));
}
$eventId = $this->Attribute->data['Attribute']['event_id'];
$this->Attribute->Event->recursive = -1;
$event = $this->Attribute->Event->read(array(), $eventId);
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status' => 200, 'type' => 'json'));
}
}
if (!$this->_isRest()) {
$this->Attribute->Event->insertLock($this->Auth->user(), $eventId);
}
$this->Attribute->recursive = -1;
foreach ($tag_id_list as $tag_id) {
$this->Attribute->AttributeTag->Tag->id = $tag_id;
if (!$this->Attribute->AttributeTag->Tag->exists()) {
$fails++;
continue;
}
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (!empty($found)) {
$fails++;
continue;
}
$this->Attribute->AttributeTag->create();
if ($this->Attribute->AttributeTag->save(array('attribute_id' => $id, 'tag_id' => $tag_id, 'event_id' => $eventId))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to attribute (' . $id . ')', 'Attribute (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success++;
} else {
$fails++;
}
}
}
if ($fails == 0) {
if ($success == 1) {
$message = 'Tag added.';
} else {
$message = $success . ' tags added.';
}
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $message, 'check_publish' => true)), 'status' => 200, 'type' => 'json'));
if (!$this->request->is('post')) {
$this->set('object_id', $id);
$this->set('scope', 'Attribute');
$this->layout = false;
$this->autoRender = false;
$this->render('/Events/add_tag');
} else {
if ($fails == 1) {
$message = 'Tag could not be added.';
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
if (!is_numeric($tag_id)) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
// try to parse json array
$tag_ids = json_decode($tag_id);
if ($tag_ids !== null) { // can decode json
$tag_id_list = array();
foreach ($tag_ids as $tag_id) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_id_list[] = $tag_id;
}
}
} else {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
}
if (!isset($idList)) {
$idList = array($id);
}
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
$success = 0;
$fails = 0;
foreach ($idList as $id) {
$this->Attribute->id = $id;
if (!$this->Attribute->exists()) {
throw new NotFoundException(__('Invalid attribute'));
}
$this->Attribute->read();
if (!$this->_isSiteAdmin() && $this->Attribute->data['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
$fails++;
continue;
}
if ($this->Attribute->data['Attribute']['deleted']) {
throw new NotFoundException(__('Invalid attribute'));
}
$eventId = $this->Attribute->data['Attribute']['event_id'];
$this->Attribute->Event->recursive = -1;
$event = $this->Attribute->Event->read(array(), $eventId);
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['org_id'] && $this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status' => 200, 'type' => 'json'));
}
}
if (!$this->_isRest()) {
$this->Attribute->Event->insertLock($this->Auth->user(), $eventId);
}
$this->Attribute->recursive = -1;
foreach ($tag_id_list as $tag_id) {
$this->Attribute->AttributeTag->Tag->id = $tag_id;
if (!$this->Attribute->AttributeTag->Tag->exists()) {
$fails++;
continue;
}
$tag = $this->Attribute->AttributeTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Attribute->AttributeTag->find('first', array(
'conditions' => array(
'attribute_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
$this->autoRender = false;
if (!empty($found)) {
$fails++;
continue;
}
$this->Attribute->AttributeTag->create();
if ($this->Attribute->AttributeTag->save(array('attribute_id' => $id, 'tag_id' => $tag_id, 'event_id' => $eventId))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Attribute->Event->save($event);
$this->Attribute->data['Attribute']['timestamp'] = $date->getTimestamp();
$this->Attribute->save($this->Attribute->data);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Attribute', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to attribute (' . $id . ')', 'Attribute (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success++;
} else {
$fails++;
}
}
}
if ($fails == 0) {
if ($success == 1) {
$message = 'Tag added.';
} else {
$message = $success . ' tags added.';
}
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $message, 'check_publish' => true)), 'status' => 200, 'type' => 'json'));
} else {
$message = $fails . ' tags could not be added.';
if ($fails == 1) {
$message = 'Tag could not be added.';
} else {
$message = $fails . ' tags could not be added.';
}
if ($success > 0) {
$message .= ' However, ' . $success . ' tag(s) were added.';
}
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $message)), 'status' => 200, 'type' => 'json'));
}
if ($success > 0) {
$message .= ' However, ' . $success . ' tag(s) were added.';
}
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $message)), 'status' => 200, 'type' => 'json'));
}
}

View File

@ -115,6 +115,7 @@ class ACLComponent extends Component
'getEventGraphReferences' => array('*'),
'getEventGraphTags' => array('*'),
'getEventGraphGeneric' => array('*'),
'genDistributionGraph' => array('*'),
'getDistributionGraph' => array('*'),
'getReferenceData' => array('*'),
'getReferences' => array('*'),
@ -129,6 +130,7 @@ class ACLComponent extends Component
'proposalEventIndex' => array('*'),
'publish' => array('perm_publish'),
'pushEventToZMQ' => array('perm_publish_zmq'),
'pushEventToKafka' => array('perm_publish_kafka'),
'pushProposals' => array('perm_sync'),
'queryEnrichment' => array('perm_add'),
'removePivot' => array('*'),
@ -165,6 +167,7 @@ class ACLComponent extends Component
'disable' => array(),
'edit' => array(),
'enable' => array(),
'feedCoverage' => array('*'),
'fetchFromAllFeeds' => array(),
'fetchFromFeed' => array(),
'fetchSelectedFromFreetextIndex' => array(),
@ -179,6 +182,7 @@ class ACLComponent extends Component
'galaxies' => array(
'attachCluster' => array('perm_tagger'),
'attachMultipleClusters' => array('perm_tagger'),
'delete' => array(),
'index' => array('*'),
'selectGalaxy' => array('perm_tagger'),
'selectGalaxyNamespace' => array('perm_tagger'),
@ -193,7 +197,8 @@ class ACLComponent extends Component
'delete' => array('perm_site_admin'),
'detach' => array('perm_tagger'),
'index' => array('*'),
'view' => array('*')
'view' => array('*'),
'viewGalaxyMatrix' => array('*')
),
'galaxyElements' => array(
'index' => array('*')
@ -302,6 +307,10 @@ class ACLComponent extends Component
'cleanRegexModifiers' => array('perm_regexp_access'),
'index' => array('*'),
),
'restClientHistory' => array(
'delete' => array('*'),
'index' => array('*')
),
'roles' => array(
'admin_add' => array(),
'admin_delete' => array(),
@ -429,8 +438,13 @@ class ACLComponent extends Component
'enable' => array(),
'index' => array('*'),
'taxonomyMassConfirmation' => array('perm_tagger'),
'taxonomyMassHide' => array('perm_tagger'),
'taxonomyMassUnhide' => array('perm_tagger'),
'toggleRequired' => array('perm_site_admin'),
'update' => array(),
'view' => array('*'),
'unhideTag' => array('perm_tagger'),
'hideTag' => array('perm_tagger'),
),
'templateElements' => array(
'add' => array('perm_template'),

View File

@ -38,6 +38,17 @@ class ApacheAuthenticate extends BaseAuthenticate
}
return $returnCode;
}
private function getEmailAddress($ldapEmailField, $ldapUserData)
{
// return the email address of an LDAP user if one of the fields in $ldapEmaiLField exists
foreach($ldapEmailField as $field) {
if (isset($ldapUserData[0][$field][0])) {
return $ldapUserData[0][$field][0];
}
}
return NULL;
}
public function authenticate(CakeRequest $request, CakeResponse $response)
{
@ -51,6 +62,7 @@ class ApacheAuthenticate extends BaseAuthenticate
$ldaprdn = Configure::read('ApacheSecureAuth.ldapReaderUser'); // DN ou RDN LDAP
$ldappass = Configure::read('ApacheSecureAuth.ldapReaderPassword');
$ldapSearchFilter = Configure::read('ApacheSecureAuth.ldapSearchFilter');
$ldapEmailField = Configure::read('ApacheSecureAuth.ldapEmailField');
// LDAP connection
ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, Configure::read('ApacheSecureAuth.ldapNetworkTimeout', -1));
@ -83,13 +95,17 @@ class ApacheAuthenticate extends BaseAuthenticate
$ldapUserData = ldap_get_entries($ldapconn, $result);
// the request returns only 1 field
if (isset($ldapUserData[0]['mail'][0])) {
// find the email address in the query's result
// first if the ldapEmailField option is not specified, look for the email address in the default field
if (!isset($ldapEmailField) && isset($ldapUserData[0]['mail'][0])) {
// assign the real user for MISP
$mispUsername = $ldapUserData[0]['mail'][0];
} else if (isset($ldapEmailField)) {
$mispUsername = $this->getEmailAddress($ldapEmailField, $ldapUserData);
} else {
die("User not found in LDAP");
}
// close LDAP connection
ldap_close($ldapconn);
}

View File

@ -243,6 +243,10 @@ class RestResponseComponent extends Component
'description' => "POST a body and a subject in a JSON to send an e-mail through MISP to the user ID given in the URL",
'mandatory' => array('subject', 'body')
),
'change_pw' => array(
'description' => "POST a password via a JSON object containing the password key to reset the given user\'s password.",
'mandatory' => array('password')
),
'statistics' => array(
'description' => 'Simply GET the url endpoint to view the API output of the statistics API. Additional statistics are available via the following tab-options similar to the UI: data, orgs, users, tags, attributehistogram, sightings, attackMatrix',
'params' => array('tab'),

View File

@ -26,7 +26,7 @@ class EventsController extends AppController
);
private $acceptedFilteringNamedParams = array('sort', 'direction', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'attributeFilter', 'extended', 'page',
'searchFor', 'attributeFilter', 'proposal', 'correlation', 'warning', 'deleted', 'includeRelatedTags', 'distribution', 'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'feed', 'server', 'toIDS'
'searchFor', 'proposal', 'correlation', 'warning', 'deleted', 'includeRelatedTags', 'distribution', 'taggedAttributes', 'galaxyAttachedAttributes', 'objectType', 'attributeType', 'focus', 'extended', 'overrideLimit', 'filterColumnsOverwrite', 'feed', 'server', 'toIDS'
);
public $defaultFilteringRules = array(
@ -296,19 +296,31 @@ class EventsController extends AppController
$passedArgsArray = array();
$urlparams = "";
$overrideAbleParams = array('all', 'attribute', 'published', 'eventid', 'datefrom', 'dateuntil', 'org', 'eventinfo', 'tag', 'tags', 'distribution', 'sharinggroup', 'analysis', 'threatlevel', 'email', 'hasproposal', 'timestamp', 'publishtimestamp', 'publish_timestamp', 'minimal');
$paginationParams = array('limit', 'page', 'sort', 'direction', 'order');
$passedArgs = $this->passedArgs;
if (isset($this->request->data)) {
if (isset($this->request->data['request'])) {
$this->request->data = $this->request->data['request'];
}
foreach ($overrideAbleParams as $oap) {
if (isset($this->request->data['search' . $oap])) {
$this->request->data[$oap] = $this->request->data['search' . $oap];
foreach ($this->request->data as $k => $v) {
if (substr($k, 0, 6) === 'search' && in_array(strtolower(substr($k, 6)), $overrideAbleParams)) {
unset($this->request->data[$k]);
$this->request->data[strtolower(substr($k, 6))] = $v;
} else if (in_array(strtolower($k), $overrideAbleParams)) {
unset($this->request->data[$k]);
$this->request->data[strtolower($k)] = $v;
}
}
foreach ($overrideAbleParams as $oap) {
if (isset($this->request->data[$oap])) {
$passedArgs['search' . $oap] = $this->request->data[$oap];
}
}
foreach ($paginationParams as $paginationParam) {
if (isset($this->request->data[$paginationParam])) {
$passedArgs[$paginationParam] = $this->request->data[$paginationParam];
}
}
}
$this->set('passedArgs', json_encode($passedArgs));
// check each of the passed arguments whether they're a filter (could also be a sort for example) and if yes, add it to the pagination conditions
@ -699,12 +711,6 @@ class EventsController extends AppController
} else {
$rules['order'] = array('Event.id' => 'DESC');
}
if (isset($passedArgs['limit'])) {
$rules['limit'] = intval($passedArgs['limit']);
}
if (isset($passedArgs['page'])) {
$rules['page'] = intval($passedArgs['page']);
}
$rules['contain'] = $this->paginate['contain'];
if (isset($this->paginate['conditions'])) {
$rules['conditions'] = $this->paginate['conditions'];
@ -714,6 +720,12 @@ class EventsController extends AppController
$rules['recursive'] = -1;
$rules['fields'] = array('id', 'timestamp', 'published', 'uuid');
}
$paginationRules = array('page', 'limit', 'sort', 'direction', 'order');
foreach ($paginationRules as $paginationRule) {
if (isset($passedArgs[$paginationRule])) {
$rules[$paginationRule] = $passedArgs[$paginationRule];
}
}
if (empty($rules['limit'])) {
$events = array();
$i = 1;
@ -856,6 +868,7 @@ class EventsController extends AppController
$this->set('analysisLevels', $this->Event->analysisLevels);
$this->set('distributionLevels', $this->Event->distributionLevels);
$this->set('shortDist', $this->Event->shortDist);
$this->set('distributionData', $this->genDistributionGraph(-1));
if ($this->params['ext'] === 'csv') {
App::uses('CsvExport', 'Export');
$export = new CsvExport();
@ -1444,6 +1457,7 @@ class EventsController extends AppController
$orgTable = $this->Event->Orgc->find('list', array(
'fields' => array('Orgc.id', 'Orgc.name')
));
$this->set('required_taxonomies', $this->Event->getRequiredTaxonomies());
$this->set('orgTable', $orgTable);
$this->set('currentUri', $attributeUri);
$this->set('filters', $filters);
@ -2350,6 +2364,18 @@ class EventsController extends AppController
$result = $this->Event->save($event, array('fieldList' => $fieldList));
if ($result) {
$message = __('Event unpublished.');
$kafkaTopic = Configure::read('Plugin.Kafka_event_publish_notifications_topic');
if (Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_event_publish_notifications_enable') && !empty($kafkaTopic)) {
$kafkaPubTool = $this->Event->getKafkaPubTool();
$params = array('eventid' => $id);
if (Configure::read('Plugin.Kafka_include_attachments')) {
$params['includeAttachments'] = 1;
}
$pubEvent = $this->Event->fetchEvent($this->Auth->user(), $params);
if (!empty($pubEvent)) {
$kafkaPubTool->publishJson($kafkaTopic, $pubEvent[0], 'unpublish');
}
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('events', 'unpublish', $id, false, $message);
} else {
@ -2387,6 +2413,13 @@ class EventsController extends AppController
$errors = array();
// only allow form submit CSRF protection.
if ($this->request->is('post') || $this->request->is('put')) {
if (!$this->_isRest()) {
$publishable = $this->Event->checkIfPublishable($id);
if ($publishable !== true) {
$this->Flash->error(__('Could not publish event - no tag for required taxonomies missing: %s', implode(', ', $publishable)));
$this->redirect(array('action' => 'view', $id));
}
}
// Performs all the actions required to publish an event
$result = $this->Event->publishRouter($id, null, $this->Auth->user());
if (!Configure::read('MISP.background_jobs')) {
@ -3518,9 +3551,6 @@ class EventsController extends AppController
public function addTag($id = false, $tag_id = false)
{
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
$rearrangeRules = array(
'request' => false,
'Event' => false,
@ -3533,112 +3563,120 @@ class EventsController extends AppController
if ($id === false) {
$id = $this->request->data['event'];
}
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
$conditions = array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)));
if (!$this->_isSiteAdmin()) {
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
}
if (!is_numeric($tag_id)) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_ids = json_decode($tag_id);
if ($tag_ids !== null) { // can decode json
$tag_id_list = array();
foreach ($tag_ids as $tag_id) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_id_list[] = $tag_id;
}
}
} else {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
}
$this->Event->recursive = -1;
$event = $this->Event->read(array(), $id);
if (empty($event)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid event.')), 'status'=>200, 'type' => 'json'));
}
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
}
$this->autoRender = false;
$error = false;
$success = false;
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
foreach ($tag_id_list as $tag_id) {
$this->Event->EventTag->Tag->id = $tag_id;
if (!$this->Event->EventTag->Tag->exists()) {
$error = __('Invalid Tag.');
continue;
}
$tag = $this->Event->EventTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Event->EventTag->find('first', array(
'conditions' => array(
'event_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
if (!empty($found)) {
$error = __('Tag is already attached to this event.');
continue;
}
$this->Event->EventTag->create();
if ($this->Event->EventTag->save(array('event_id' => $id, 'tag_id' => $tag_id))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Event->save($event);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Event', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to event (' . $id . ')', 'Event (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success = __('Tag(s) added.');
} else {
$fail = __('Tag could not be added.');
}
}
if ($success) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('Tag(s) added.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} elseif (empty($fail)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('All tags are already present, nothing to add.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
if (!$this->request->is('post')) {
$this->set('object_id', $id);
$this->set('scope', 'Event');
$this->layout = false;
$this->autoRender = false;
$this->render('/Events/add_tag');
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $fail)), 'status'=>200, 'type' => 'json'));
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
if (!$this->_isSiteAdmin() && !$this->userRole['perm_sync']) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $event['Event']['orgc_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
}
$conditions = array('LOWER(Tag.name) LIKE' => strtolower(trim($tag_id)));
if (!$this->_isSiteAdmin()) {
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
}
if (!is_numeric($tag_id)) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_ids = json_decode($tag_id);
if ($tag_ids !== null) { // can decode json
$tag_id_list = array();
foreach ($tag_ids as $tag_id) {
if (preg_match('/^collection_[0-9]+$/i', $tag_id)) {
$tagChoice = explode('_', $tag_id)[1];
$this->loadModel('TagCollection');
$tagCollection = $this->TagCollection->fetchTagCollection($this->Auth->user(), array('conditions' => array('TagCollection.id' => $tagChoice)));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag Collection.')), 'status'=>200, 'type' => 'json'));
}
$tag_id_list = array();
foreach ($tagCollection[0]['TagCollectionTag'] as $tagCollectionTag) {
$tag_id_list[] = $tagCollectionTag['tag_id'];
}
} else {
$tag_id_list[] = $tag_id;
}
}
} else {
$tag = $this->Event->EventTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
}
$this->autoRender = false;
$error = false;
$success = false;
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
foreach ($tag_id_list as $tag_id) {
$this->Event->EventTag->Tag->id = $tag_id;
if (!$this->Event->EventTag->Tag->exists()) {
$error = __('Invalid Tag.');
continue;
}
$tag = $this->Event->EventTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->Event->EventTag->find('first', array(
'conditions' => array(
'event_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
if (!empty($found)) {
$error = __('Tag is already attached to this event.');
continue;
}
$this->Event->EventTag->create();
if ($this->Event->EventTag->save(array('event_id' => $id, 'tag_id' => $tag_id))) {
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Event->save($event);
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'Event', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to event (' . $id . ')', 'Event (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success = __('Tag(s) added.');
} else {
$fail = __('Tag could not be added.');
}
}
if ($success) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('Tag(s) added.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} elseif (empty($fail)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('All tags are already present, nothing to add.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $fail)), 'status'=>200, 'type' => 'json'));
}
}
}
@ -4655,8 +4693,7 @@ class EventsController extends AppController
return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json'));
}
public function getDistributionGraph($id, $type = 'event')
{
private function genDistributionGraph($id, $type = 'event', $extended = 0) {
$validTools = array('event');
if (!in_array($type, $validTools)) {
throw new MethodNotAllowedException(__('Invalid type.'));
@ -4665,9 +4702,6 @@ class EventsController extends AppController
$this->loadModel('Organisation');
App::uses('DistributionGraphTool', 'Tools');
$grapher = new DistributionGraphTool();
$data = $this->request->is('post') ? $this->request->data : array();
$extended = isset($this->params['named']['extended']) ? 1 : 0;
$servers = $this->Server->find('list', array(
'fields' => array('name'),
@ -4680,6 +4714,13 @@ class EventsController extends AppController
$item = utf8_encode($item);
}
});
return $json;
}
public function getDistributionGraph($id, $type = 'event')
{
$extended = isset($this->params['named']['extended']) ? 1 : 0;
$json = $this->genDistributionGraph($id, $type, $extended);
$this->response->type('json');
return new CakeResponse(array('body' => json_encode($json), 'status' => 200, 'type' => 'json'));
}
@ -4903,7 +4944,6 @@ class EventsController extends AppController
App::uses('ColourGradientTool', 'Tools');
$gradientTool = new ColourGradientTool();
$colours = $gradientTool->createGradientFromValues($scores);
$this->set('eventId', $eventId);
$this->set('target_type', $scope);
$this->set('columnOrders', $killChainOrders);
@ -4986,12 +5026,12 @@ class EventsController extends AppController
if (empty($attribute)) {
throw new MethodNotAllowedException(__('Attribute not found or you are not authorised to see it.'));
}
$this->loadModel('Module');
$enabledModules = $this->Module->getEnabledModules($this->Auth->user(), false, $type);
if (!is_array($enabledModules) || empty($enabledModules)) {
throw new MethodNotAllowedException(__('No valid %s options found for this attribute.', $type));
}
if ($this->request->is('ajax')) {
$this->loadModel('Module');
$enabledModules = $this->Module->getEnabledModules($this->Auth->user(), false, $type);
if (!is_array($enabledModules) || empty($enabledModules)) {
throw new MethodNotAllowedException(__('No valid %s options found for this attribute.', $type));
}
$modules = array();
foreach ($enabledModules['modules'] as $module) {
if (in_array($attribute[0]['Attribute']['type'], $module['mispattributes']['input'])) {
@ -5004,65 +5044,16 @@ class EventsController extends AppController
$this->set('type', $type);
$this->render('ajax/enrichmentChoice');
} else {
$this->loadModel('Module');
$enabledModules = $this->Module->getEnabledModules($this->Auth->user(), false, $type);
if (!is_array($enabledModules) || empty($enabledModules)) {
throw new MethodNotAllowedException(__('no valid %s options found for this attribute.', $type));
}
$options = array();
foreach ($enabledModules['modules'] as $temp) {
if ($temp['name'] == $module) {
$format = (isset($temp['mispattributes']['format']) ? $temp['mispattributes']['format'] : 'simplified');
if (isset($temp['meta']['config'])) {
foreach ($temp['meta']['config'] as $conf) {
$options[$conf] = Configure::read('Plugin.' . $type . '_' . $module . '_' . $conf);
}
}
}
}
$data = array('module' => $module, $attribute[0]['Attribute']['type'] => $attribute[0]['Attribute']['value'], 'event_id' => $attribute[0]['Attribute']['event_id'], 'attribute_uuid' => $attribute[0]['Attribute']['uuid']);
if ($this->Event->Attribute->typeIsAttachment($attribute[0]['Attribute']['type'])) {
$data['data'] = $this->Event->Attribute->base64EncodeAttachment($attribute[0]['Attribute']);
}
if (!empty($options)) {
$data['config'] = $options;
}
$data = json_encode($data);
$result = $this->Module->queryModuleServer('/query', $data, false, $type);
if (!$result) {
throw new MethodNotAllowedException(__('%s service not reachable.', $type));
}
if (isset($result['error'])) {
$this->Flash->error($result['error']);
}
if (!is_array($result)) {
throw new Exception($result);
}
$resultArray = $this->Event->handleModuleResult($result, $attribute[0]['Attribute']['event_id']);
if (isset($result['comment']) && $result['comment'] != "") {
$importComment = $result['comment'];
} else {
$importComment = $attribute[0]['Attribute']['value'] . __(': Enriched via the %s', $module) . ($type != 'Enrichment' ? ' ' . $type : '') . ' module';
}
$typeCategoryMapping = array();
foreach ($this->Event->Attribute->categoryDefinitions as $k => $cat) {
foreach ($cat['types'] as $type) {
$typeCategoryMapping[$type][$k] = $k;
}
}
foreach ($resultArray as $key => $result) {
$options = array(
'conditions' => array('OR' => array('Attribute.value1' => $result['value'], 'Attribute.value2' => $result['value'])),
'fields' => array('Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.comment'),
'order' => false
);
$resultArray[$key]['related'] = $this->Event->Attribute->fetchAttributes($this->Auth->user(), $options);
if (isset($result['data'])) {
App::uses('FileAccessTool', 'Tools');
$fileAccessTool = new FileAccessTool();
$tmpdir = Configure::read('MISP.tmpdir') ? Configure::read('MISP.tmpdir') : '/tmp';
$tempFile = $fileAccessTool->createTempFile($tmpdir, $prefix = 'MISP');
$fileAccessTool->writeToFile($tempFile, $result['data']);
$resultArray[$key]['data'] = basename($tempFile) . '|' . filesize($tempFile);
break;
}
}
$distributions = $this->Event->Attribute->distributionLevels;
@ -5072,18 +5063,133 @@ class EventsController extends AppController
}
$this->set('distributions', $distributions);
$this->set('sgs', $sgs);
$this->set('type', $type);
$this->set('event', array('Event' => $attribute[0]['Event']));
$this->set('resultArray', $resultArray);
$this->set('typeList', array_keys($this->Event->Attribute->typeDefinitions));
$this->set('defaultCategories', $this->Event->Attribute->defaultCategories);
$this->set('typeCategoryMapping', $typeCategoryMapping);
$this->set('title', 'Enrichment Results');
$this->set('importComment', $importComment);
$this->render('resolved_attributes');
if ($format == 'misp_standard') {
$this->__queryEnrichment($attribute, $module, $options, $type);
} else {
$this->__queryOldEnrichment($attribute, $module, $options, $type);
}
}
}
private function __queryEnrichment($attribute, $module, $options, $type)
{
if ($this->Event->Attribute->typeIsAttachment($attribute[0]['Attribute']['type'])) {
$attribute[0]['Attribute']['data'] = $this->Event->Attribute->base64EncodeAttachment($attribute[0]['Attribute']);
}
$event_id = $attribute[0]['Event']['id'];
$data = array('module' => $module, 'attribute' => $attribute[0]['Attribute'], 'event_id' => $event_id);
if (!empty($options)) {
$data['config'] = $options;
}
$data = json_encode($data);
$result = $this->Module->queryModuleServer('/query', $data, false, $type);
if (!$result) {
throw new MethodNotAllowedException(__('%s service not reachable.', $type));
}
if (isset($result['error'])) {
$this->Flash->error($result['error']);
}
if (!is_array($result)) {
throw new Exception($result);
}
$attributes = array();
$objects = array();
if (isset($result['results']['Attribute']) && !empty($result['results']['Attribute'])) {
foreach ($result['results']['Attribute'] as $tmp_attribute) {
array_push($attributes, $this->Event->Attribute->captureAttribute($tmp_attribute, $event_id, $this->Auth->user()));
}
unset($result['results']['Attribute']);
}
if (isset($result['results']['Object']) && !empty($result['results']['Object'])) {
foreach ($result['results']['Object'] as $tmp_object) {
$this->Event->Object->captureObject($tmp_object, $event_id, $this->Auth->user());
array_push($objects, $tmp_object);
}
unset($result['results']['Object']);
}
if (empty($attributes) && empty($objects)) {
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type);
} else {
$event = array('Event' => $attribute[0]['Event']);
$event['Attribute'] = $attributes;
$event['Object'] = $objects;
$this->set('event', $event);
if (!empty($result['results'])) {
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type, $event = true, $render_name = 'resolved_misp_format');
} else {
$this->set('menuItem', 'enrichmentResults');
$this->set('title', 'Enrichment Results');
$this->render('resolved_misp_format');
}
}
}
private function __queryOldEnrichment($attribute, $module, $options, $type)
{
$data = array('module' => $module, $attribute[0]['Attribute']['type'] => $attribute[0]['Attribute']['value'], 'event_id' => $attribute[0]['Attribute']['event_id'], 'attribute_uuid' => $attribute[0]['Attribute']['uuid']);
if ($this->Event->Attribute->typeIsAttachment($attribute[0]['Attribute']['type'])) {
$data['data'] = $this->Event->Attribute->base64EncodeAttachment($attribute[0]['Attribute']);
}
if (!empty($options)) {
$data['config'] = $options;
}
$data = json_encode($data);
$result = $this->Module->queryModuleServer('/query', $data, false, $type);
if (!$result) {
throw new MethodNotAllowedException(__('%s service not reachable.', $type));
}
if (isset($result['error'])) {
$this->Flash->error($result['error']);
}
if (!is_array($result)) {
throw new Exception($result);
}
$this->__handleSimplifiedFormat($attribute, $module, $options, $result, $type);
}
private function __handleSimplifiedFormat($attribute, $module, $options, $result, $type, $event = false, $renderName = 'resolved_attributes')
{
$resultArray = $this->Event->handleModuleResult($result, $attribute[0]['Attribute']['event_id']);
if (isset($result['comment']) && $result['comment'] != "") {
$importComment = $result['comment'];
} else {
$importComment = $attribute[0]['Attribute']['value'] . __(': Enriched via the %s', $module) . ($type != 'Enrichment' ? ' ' . $type : '') . ' module';
}
$typeCategoryMapping = array();
foreach ($this->Event->Attribute->categoryDefinitions as $k => $cat) {
foreach ($cat['types'] as $type) {
$typeCategoryMapping[$type][$k] = $k;
}
}
foreach ($resultArray as $key => $result) {
$options = array(
'conditions' => array('OR' => array('Attribute.value1' => $result['value'], 'Attribute.value2' => $result['value'])),
'fields' => array('Attribute.type', 'Attribute.category', 'Attribute.value', 'Attribute.comment'),
'order' => false
);
$resultArray[$key]['related'] = $this->Event->Attribute->fetchAttributes($this->Auth->user(), $options);
if (isset($result['data'])) {
App::uses('FileAccessTool', 'Tools');
$fileAccessTool = new FileAccessTool();
$tmpdir = Configure::read('MISP.tmpdir') ? Configure::read('MISP.tmpdir') : '/tmp';
$tempFile = $fileAccessTool->createTempFile($tmpdir, $prefix = 'MISP');
$fileAccessTool->writeToFile($tempFile, $result['data']);
$resultArray[$key]['data'] = basename($tempFile) . '|' . filesize($tempFile);
}
}
$this->set('type', $type);
if (!$event){
$this->set('event', array('Event' => $attribute[0]['Event']));
}
$this->set('resultArray', $resultArray);
$this->set('typeList', array_keys($this->Event->Attribute->typeDefinitions));
$this->set('defaultCategories', $this->Event->Attribute->defaultCategories);
$this->set('typeCategoryMapping', $typeCategoryMapping);
$this->set('title', 'Enrichment Results');
$this->set('importComment', $importComment);
$this->render($renderName);
}
public function importModule($module, $eventId)
{
$this->loadModel('Module');
@ -5339,6 +5445,59 @@ class EventsController extends AppController
}
}
public function pushEventToKafka($id)
{
if ($this->request->is('Post')) {
$message = 'Kafka event publishing not enabled.';
if (Configure::read('Plugin.Kafka_enable')) {
$kafkaEventTopic = Configure::read('Plugin.Kafka_event_notifications_topic');
$event = $this->Event->quickFetchEvent(array('eventid' => $id));
if (Configure::read('Plugin.Kafka_event_notifications_enable') && !empty($kafkaEventTopic)) {
$kafkaPubTool = $this->Event->getKafkaPubTool();
if (!empty($event)) {
$kafkaPubTool->publishJson($kafkaEventTopic, $event, 'manual_publish');
$success = 1;
$message = 'Event published to Kafka';
} else {
$success = 0;
$message = 'Invalid event.';
}
}
$kafkaPubTopic = Configure::read('Plugin.Kafka_event_publish_notifications_topic');
if (!empty($event['Event']['published']) && Configure::read('Plugin.Kafka_event_publish_notifications_enable') && !empty($kafkaPubTopic)) {
$kafkaPubTool = $this->Event->getKafkaPubTool();
$params = array('eventid' => $id);
if (Configure::read('Plugin.Kafka_include_attachments')) {
$params['includeAttachments'] = 1;
}
$event = $this->Event->fetchEvent($this->Auth->user(), $params);
if (!empty($event)) {
$kafkaPubTool->publishJson($kafkaPubTopic, $event[0], 'manual_publish');
if (!isset($success)) {
$success = 1;
$message = 'Event published to Kafka';
}
} else {
$success = 0;
$message = 'Invalid event.';
}
}
}
} else {
$message = 'This functionality is only available via POST requests';
}
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Events', 'pushEventToKafka', $id, $this->response->type(), $message);
} else {
if (!empty($success)) {
$this->Flash->success($message);
} else {
$this->Flash->error($message);
}
$this->redirect($this->referer());
}
}
public function getEventInfoById($id)
{
if (empty($id)) {

View File

@ -23,6 +23,7 @@ class FeedsController extends AppController
{
parent::beforeFilter();
$this->Security->unlockedActions[] = 'previewIndex';
$this->Security->unlockedActions[] = 'feedCoverage';
if (!$this->_isSiteAdmin() && $this->Auth->user('org_id') != Configure::read('MISP.host_org_id')) {
throw new MethodNotAllowedException(__('You don\'t have the required privileges to do that.'));
}
@ -88,12 +89,32 @@ class FeedsController extends AppController
'recursive' => -1,
'contain' => array('Tag')
));
$feed['Feed']['cached_elements'] = $this->Feed->getCachedElements($feed['Feed']['id']);
$feed['Feed']['coverage_by_other_feeds'] = $this->Feed->getFeedCoverage($feed['Feed']['id'], 'feed', 'all') . '%';
if ($this->_isRest()) {
if (empty($feed['Tag']['id'])) {
unset($feed['Tag']);
}
return $this->RestResponse->viewData($feed, $this->response->type());
}
$feeds = $this->Feed->getAllCachingEnabledFeeds($feed['Feed']['id'], true);
$this->set('other_feeds', $feeds);
$this->set('feed', $feed);
}
public function feedCoverage($feedId)
{
if (!$this->_isSiteAdmin() && !$this->Auth->user('org_id') == Configure::read('MISP.host_org_id')) {
throw NotAllowedException('You don\'t have access to this feature.');
}
$feed = $this->Feed->find('first', array(
'conditions' => array('Feed.id' => $feedId),
'recursive' => -1,
'contain' => array('Tag')
));
$result = $this->Feed->getFeedCoverage($feed['Feed']['id'], 'feed', $this->request->data);
return $this->RestResponse->viewData($result, $this->response->type());
}
public function importFeeds()
@ -238,6 +259,7 @@ class FeedsController extends AppController
throw new NotFoundException(__('Invalid feed.'));
}
$this->Feed->read();
$this->set('feed', $this->Feed->data);
$this->loadModel('Event');
$sgs = $this->Event->SharingGroup->fetchAllAuthorised($this->Auth->user(), 'name', 1);
$distributionLevels = $this->Event->distributionLevels;

View File

@ -77,6 +77,38 @@ class GalaxiesController extends AppController
}
}
public function delete($id)
{
if (!is_numeric($id)) {
throw new NotFoundException('Invalid galaxy.');
}
$galaxy = $this->Galaxy->find('first', array(
'recursive' => -1,
'conditions' => array('Galaxy.id' => $id)
));
if (empty($galaxy)) {
throw new NotFoundException('Invalid galaxy.');
}
$result = $this->Galaxy->delete($id);
if ($result) {
$message = 'Galaxy deleted';
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Galaxy', 'delete', false, $this->response->type(), $message);
} else {
$this->Flash->success($message);
$this->redirect(array('controller' => 'galaxies', 'action' => 'index'));
}
} else {
$message = 'Could not delete Galaxy.';
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Galaxy', 'delete', false, $message);
} else {
$this->Flash->success($message);
$this->redirect($this->referer());
}
}
}
public function selectGalaxy($target_id, $target_type='event', $namespace='misp')
{
$mitreAttackGalaxyId = $this->Galaxy->getMitreAttackGalaxyId();
@ -238,34 +270,42 @@ class GalaxiesController extends AppController
public function attachMultipleClusters($target_id, $target_type = 'event')
{
if ($target_id === 'selected') {
$target_id_list = json_decode($this->request->data['Galaxy']['attribute_ids']);
} else {
$target_id_list = array($target_id);
}
$cluster_ids = $this->request->data['Galaxy']['target_ids'];
if (!empty($cluster_ids)) {
$cluster_ids = json_decode($cluster_ids, true);
if ($cluster_ids === null) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('Failed to parse request.'))), 'status'=>200, 'type' => 'json'));
if ($this->request->is('post')) {
if ($target_id === 'selected') {
$target_id_list = json_decode($this->request->data['Galaxy']['attribute_ids']);
} else {
$target_id_list = array($target_id);
}
$cluster_ids = $this->request->data['Galaxy']['target_ids'];
if (!empty($cluster_ids)) {
$cluster_ids = json_decode($cluster_ids, true);
if ($cluster_ids === null) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('Failed to parse request.'))), 'status'=>200, 'type' => 'json'));
}
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('No clusters picked.'))), 'status'=>200, 'type' => 'json'));
}
$result = "";
if (!is_array($cluster_ids)) { // in case we only want to attach 1
$cluster_ids = array($cluster_ids);
}
foreach ($cluster_ids as $cluster_id) {
foreach ($target_id_list as $target_id) {
$result = $this->Galaxy->attachCluster($this->Auth->user(), $target_type, $target_id, $cluster_id);
}
}
if ($this->request->is('ajax')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result, 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
$this->Flash->info($result);
$this->redirect($this->referer());
}
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'error' => __('No clusters picked.'))), 'status'=>200, 'type' => 'json'));
}
$result = "";
if (!is_array($cluster_ids)) { // in case we only want to attach 1
$cluster_ids = array($cluster_ids);
}
foreach ($cluster_ids as $cluster_id) {
foreach ($target_id_list as $target_id) {
$result = $this->Galaxy->attachCluster($this->Auth->user(), $target_type, $target_id, $cluster_id);
}
}
if ($this->request->is('ajax')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $result, 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
$this->Flash->info($result);
$this->redirect($this->referer());
$this->set('target_id', $target_id);
$this->set('target_type', $target_type);
$this->layout = false;
$this->autoRender = false;
$this->render('/Galaxies/ajax/attach_multiple_clusters');
}
}

View File

@ -356,4 +356,107 @@ class GalaxyClustersController extends AppController
}
}
}
public function viewGalaxyMatrix($id) {
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException('This function can only be reached via AJAX.');
}
$cluster = $this->GalaxyCluster->find('first', array(
'conditions' => array('id' => $id)
));
if (empty($cluster)) {
throw new Exception("Invalid Galaxy Cluster.");
}
$this->loadModel('Event');
$mitreAttackGalaxyId = $this->GalaxyCluster->Galaxy->getMitreAttackGalaxyId();
$attackPatternTagNames = $this->GalaxyCluster->find('list', array(
'conditions' => array('galaxy_id' => $mitreAttackGalaxyId),
'fields' => array('tag_name')
));
$cluster = $cluster['GalaxyCluster'];
$tag_name = $cluster['tag_name'];
// fetch all attribute ids having the requested cluster
$attributeIds = $this->Event->Attribute->AttributeTag->find('list', array(
'contain' => array('Tag'),
'conditions' => array(
'Tag.name' => $tag_name
),
'fields' => array('attribute_id'),
'recursive' => -1
));
// fetch all related tags belonging to attack pattern
$attributeTags = $this->Event->Attribute->AttributeTag->find('all', array(
'contain' => array('Tag'),
'conditions' => array(
'attribute_id' => $attributeIds,
'Tag.name' => $attackPatternTagNames
),
'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'),
'recursive' => -1,
'group' => array('Tag.name')
));
// fetch all event ids having the requested cluster
$eventIds = $this->Event->EventTag->find('list', array(
'contain' => array('Tag'),
'conditions' => array(
'Tag.name' => $tag_name
),
'fields' => array('event_id'),
'recursive' => -1
));
// fetch all related tags belonging to attack pattern
$eventTags = $this->Event->EventTag->find('all', array(
'contain' => array('Tag'),
'conditions' => array(
'event_id' => $eventIds,
'Tag.name' => $attackPatternTagNames
),
'fields' => array('Tag.name, COUNT(DISTINCT event_id) as tag_count'),
'recursive' => -1,
'group' => array('Tag.name')
));
$scores = array();
foreach ($attributeTags as $tag) {
$tagName = $tag['Tag']['name'];
$scores[$tagName] = intval($tag[0]['tag_count']);
}
foreach ($eventTags as $tag) {
$tagName = $tag['Tag']['name'];
if (isset($scores[$tagName])) {
$scores[$tagName] = $scores[$tagName] + intval($tag[0]['tag_count']);
} else {
$scores[$tagName] = intval($tag[0]['tag_count']);
}
}
$maxScore = count($scores) > 0 ? max(array_values($scores)) : 0;
$matrixData = $this->GalaxyCluster->Galaxy->getMatrix($mitreAttackGalaxyId);
$tabs = $matrixData['tabs'];
$matrixTags = $matrixData['matrixTags'];
$killChainOrders = $matrixData['killChain'];
$instanceUUID = $matrixData['instance-uuid'];
App::uses('ColourGradientTool', 'Tools');
$gradientTool = new ColourGradientTool();
$colours = $gradientTool->createGradientFromValues($scores);
$this->set('target_type', 'attribute');
$this->set('columnOrders', $killChainOrders);
$this->set('tabs', $tabs);
$this->set('scores', $scores);
$this->set('maxScore', $maxScore);
if (!empty($colours)) {
$this->set('colours', $colours['mapping']);
$this->set('interpolation', $colours['interpolation']);
}
$this->set('pickingMode', false);
$this->set('defaultTabName', 'mitre-attack');
$this->set('removeTrailling', 2);
$this->render('cluster_matrix');
}
}

12
app/Controller/NewsController.php Normal file → Executable file
View File

@ -48,10 +48,10 @@ class NewsController extends AppController
$this->request->data['News']['user_id'] = 0;
}
if ($this->News->save($this->request->data)) {
$this->Flash->success('News item added.');
$this->Flash->success(__('News item added.'));
$this->redirect(array('action' => 'index'));
} else {
$this->Flash->error('The news item could not be added.');
$this->Flash->error(__('The news item could not be added.'));
}
}
}
@ -65,10 +65,10 @@ class NewsController extends AppController
if ($this->request->is('post') || $this->request->is('put')) {
$this->request->data['News']['id'] = $id;
if ($this->News->save($this->request->data)) {
$this->Flash->success('News item updated.');
$this->Flash->success(__('News item updated.'));
$this->redirect(array('action' => 'index'));
} else {
$this->Flash->error('Could not update news item.');
$this->Flash->error(__('Could not update news item.'));
}
} else {
$this->request->data = $this->News->read(null, $id);
@ -86,10 +86,10 @@ class NewsController extends AppController
throw new NotFoundException('Invalid news item');
}
if ($this->News->delete()) {
$this->Flash->success('News item deleted.');
$this->Flash->success(__('News item deleted.'));
$this->redirect(array('action' => 'index'));
}
$this->Flash->error('News item could not be deleted.');
$this->Flash->error(__('News item could not be deleted.'));
$this->redirect(array('action' => 'index'));
}
}

View File

@ -198,7 +198,9 @@ class ObjectsController extends AppController
$object['Attribute'][$k]['event_id'] = $eventId;
$this->MispObject->Event->Attribute->set($attribute);
if (!$this->MispObject->Event->Attribute->validates()) {
$error = 'Could not save object as at least one attribute has failed validation (' . $attribute['object_relation'] . '). ' . json_encode($this->MispObject->Event->Attribute->validationErrors);
if ($this->MispObject->Event->Attribute->validationErrors['value'][0] !== 'Composite type found but the value not in the composite (value1|value2) format.') {
$error = 'Could not save object as at least one attribute has failed validation (' . $attribute['object_relation'] . '). ' . json_encode($this->MispObject->Event->Attribute->validationErrors);
}
}
}
}

View File

@ -25,7 +25,7 @@ class OrganisationsController extends AppController
public function index()
{
if (!$this->Auth->user('Role')['perm_sharing_group'] && Configure::read('Security.hide_organisation_index_from_users')) {
throw new MethodNotAllowedException('This feature is disabled on this instance for normal users.');
throw new MethodNotAllowedException(__('This feature is disabled on this instance for normal users.'));
}
$conditions = array();
// We can either index all of the organisations existing on this instance (default)
@ -130,14 +130,14 @@ class OrganisationsController extends AppController
));
return $this->RestResponse->viewData($org, $this->response->type());
} else {
$this->Flash->success('The organisation has been successfully added.');
$this->Flash->success(__('The organisation has been successfully added.'));
$this->redirect(array('admin' => false, 'action' => 'index'));
}
} else {
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Organisations', 'admin_add', false, $this->Organisation->validationErrors, $this->response->type());
} else {
$this->Flash->error('The organisation could not be added.');
$this->Flash->error(__('The organisation could not be added.'));
}
}
} else {
@ -152,7 +152,7 @@ class OrganisationsController extends AppController
{
$this->Organisation->id = $id;
if (!$this->Organisation->exists()) {
throw new NotFoundException('Invalid organisation');
throw new NotFoundException(__('Invalid organisation'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->_isRest()) {
@ -191,7 +191,7 @@ class OrganisationsController extends AppController
));
return $this->RestResponse->viewData($org, $this->response->type());
} else {
$this->Flash->success('Organisation updated.');
$this->Flash->success(__('Organisation updated.'));
$this->redirect(array('admin' => false, 'action' => 'view', $this->Organisation->id));
}
} else {
@ -206,7 +206,7 @@ class OrganisationsController extends AppController
));
$this->set('duplicate_org', $duplicate_org['Organisation']['id']);
}
$this->Flash->error('The organisation could not be updated.');
$this->Flash->error(__('The organisation could not be updated.'));
}
}
} else {
@ -227,11 +227,11 @@ class OrganisationsController extends AppController
public function admin_delete($id)
{
if (!$this->request->is('post')) {
throw new MethodNotAllowedException('Action not allowed, post request expected.');
throw new MethodNotAllowedException(__('Action not allowed, post request expected.'));
}
$this->Organisation->id = $id;
if (!$this->Organisation->exists()) {
throw new NotFoundException('Invalid organisation');
throw new NotFoundException(__('Invalid organisation'));
}
$org = $this->Organisation->find('first', array(
@ -272,19 +272,19 @@ class OrganisationsController extends AppController
if (Validation::uuid($id)) {
$temp = $this->Organisation->find('first', array('recursive' => -1, 'fields' => array('Organisation.id'), 'conditions' => array('Organisation.uuid' => $id)));
if (empty($temp)) {
throw new NotFoundException('Invalid organisation.');
throw new NotFoundException(__('Invalid organisation.'));
}
$id = $temp['Organisation']['id'];
} elseif (!is_numeric($id)) {
$temp = $this->Organisation->find('first', array('recursive' => -1, 'fields' => array('Organisation.id'), 'conditions' => array('Organisation.name' => urldecode($id))));
if (empty($temp)) {
throw new NotFoundException('Invalid organisation.');
throw new NotFoundException(__('Invalid organisation.'));
}
$id = $temp['Organisation']['id'];
}
$this->Organisation->id = $id;
if (!$this->Organisation->exists()) {
throw new NotFoundException('Invalid organisation');
throw new NotFoundException(__('Invalid organisation'));
}
$fullAccess = false;
$fields = array('id', 'name', 'date_created', 'date_modified', 'type', 'nationality', 'sector', 'contacts', 'description', 'local', 'uuid', 'restricted_to_domain');
@ -311,7 +311,7 @@ class OrganisationsController extends AppController
'conditions' => array('ShadowAttribute.org_id' => $org['Organisation']['id'])
));
if (empty($proposal)) {
throw new NotFoundException('Invalid organisation');
throw new NotFoundException(__('Invalid organisation'));
}
}
}
@ -344,12 +344,12 @@ class OrganisationsController extends AppController
{
$this->Organisation->id = $id;
if (!$this->Organisation->exists()) {
throw new NotFoundException('Invalid organisation');
throw new NotFoundException(__('Invalid organisation'));
}
$org = $this->Organisation->find('first', array('conditions' => array('id' => $id), 'fields' => array('landingpage', 'name')));
$landingpage = $org['Organisation']['landingpage'];
if (empty($landingpage)) {
$landingpage = "No landing page has been created for this organisation.";
$landingpage = __('No landing page has been created for this organisation.');
}
$this->set('landingPage', $landingpage);
$this->set('org', $org['Organisation']['name']);
@ -398,7 +398,7 @@ class OrganisationsController extends AppController
public function getUUIDs()
{
if (!$this->Auth->user('Role')['perm_sync']) {
throw new MethodNotAllowedException('This action is restricted to sync users');
throw new MethodNotAllowedException(__('This action is restricted to sync users'));
}
$temp = $this->Organisation->find('all', array(
'recursive' => -1,
@ -415,15 +415,15 @@ class OrganisationsController extends AppController
public function admin_merge($id, $target_id = false)
{
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException('You are not authorised to do that.');
throw new MethodNotAllowedException(__('You are not authorised to do that.'));
}
if ($this->request->is('Post')) {
$result = $this->Organisation->orgMerge($id, $this->request->data, $this->Auth->user());
if ($result) {
$this->Flash->success('The organisation has been successfully merged.');
$this->Flash->success(__('The organisation has been successfully merged.'));
$this->redirect(array('admin' => false, 'action' => 'view', $result));
} else {
$this->Flash->error('There was an error while merging the organisations. To find out more about what went wrong, refer to the audit logs. If you would like to revert the changes, you can find a .sql file ');
$this->Flash->error(__('There was an error while merging the organisations. To find out more about what went wrong, refer to the audit logs. If you would like to revert the changes, you can find a .sql file'));
}
$this->redirect(array('admin' => false, 'action' => 'index'));
} else {

View File

@ -0,0 +1,68 @@
<?php
App::uses('AppController', 'Controller');
class RestClientHistoryController extends AppController
{
public $components = array(
'Security',
'AdminCrud',
'RequestHandler'
);
public $paginate = array(
'limit' => 10,
'recursive' => -1
);
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions = array('delete');
// We don't care about CSRF protection for deleting these entries.
}
public function index($bookmarked = false)
{
$params = array(
'recursive' => -1,
'conditions' => array(
'RestClientHistory.user_id' => $this->Auth->user('id')
),
'order' => array(
'RestClientHistory.timestamp' => 'DESC'
),
);
if ($bookmarked) {
$params['conditions']['RestClientHistory.bookmark'] = $bookmarked ? 1 : 0;
}
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');
}
}
public function delete($id)
{
$entry = $this->RestClientHistory->find('first', array(
'recursive' => -1,
'conditions' => array('RestClientHistory.id' => $id, 'RestClientHistory.user_id' => $this->Auth->user('id')),
));
if (empty($entry)) {
throw new NotFoundException(__('Invalid entry.'));
}
$this->RestClientHistory->delete($id);
return $this->RestResponse->saveSuccessResponse('RestClientHistory', 'delete', $id, false, __('Entry removed.'));
}
}

View File

@ -56,7 +56,7 @@ class RolesController extends AppController
));
return $this->RestResponse->viewData($role, $this->response->type());
} else {
$this->Flash->success('The Role has been saved');
$this->Flash->success(__('The Role has been saved'));
$this->redirect(array('action' => 'index'));
}
} else {
@ -82,7 +82,7 @@ class RolesController extends AppController
}
$this->Role->id = $id;
if (!$this->Role->exists() && !$this->request->is('get')) {
throw new NotFoundException('Invalid Role');
throw new NotFoundException(__('Invalid Role'));
}
if ($this->request->is('post') || $this->request->is('put')) {
if (!isset($this->request->data['Role'])) {
@ -97,7 +97,7 @@ class RolesController extends AppController
));
return $this->RestResponse->viewData($role, $this->response->type());
} else {
$this->Flash->success('The Role has been saved');
$this->Flash->success(__('The Role has been saved'));
$this->redirect(array('action' => 'index'));
}
} else {
@ -148,7 +148,7 @@ class RolesController extends AppController
}
$this->Role->id = $id;
if (!$this->Role->exists()) {
throw new NotFoundException('Invalid Role');
throw new NotFoundException(__('Invalid Role'));
}
if ($this->Role->delete()) {
if ($this->_isRest()) {
@ -161,7 +161,7 @@ class RolesController extends AppController
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Roles', 'admin_delete', $id, $this->Role->validationErrors, $this->response->type());
} else {
$this->Flash->error('Role could not be deleted');
$this->Flash->error(__('Role could not be deleted'));
$this->redirect(array('action' => 'index'));
}
}
@ -197,7 +197,7 @@ class RolesController extends AppController
$this->loadModel('AdminSetting');
$result = $this->AdminSetting->changeSetting('default_role', $role_id);
if ($result === true) {
$message = $role_id ? 'Default role set.' : 'Default role unset.';
$message = $role_id ? __('Default role set.') : __('Default role unset.');
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Roles', 'admin_set_default', $role_id, $this->response->type(), $message);
} else {

View File

@ -215,7 +215,6 @@ class ServersController extends AppController
throw new MethodNotAllowedException('No remote org ID set. Please pass it as remote_org_id');
}
}
$fail = false;
if (empty(Configure::read('MISP.host_org_id'))) {
$this->request->data['Server']['internal'] = 0;
@ -240,7 +239,6 @@ class ServersController extends AppController
$this->Flash->error($error_msg);
}
}
if (!$fail) {
if ($this->_isRest()) {
$defaults = array(
@ -334,7 +332,7 @@ class ServersController extends AppController
}
} else {
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Servers', 'add', false, $this->Server->validationError, $this->response->type());
return $this->RestResponse->saveFailResponse('Servers', 'add', false, $this->Server->validationErrors, $this->response->type());
} else {
$this->Flash->error(__('The server could not be saved. Please, try again.'));
}
@ -1142,10 +1140,16 @@ class ServersController extends AppController
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException();
}
if (!isset($setting_name) || !isset($id)) {
if (!isset($setting_name)) {
throw new MethodNotAllowedException();
}
$this->set('id', $id);
if (!$this->_isRest()) {
if (!isset($id)) {
throw new MethodNotAllowedException();
}
$this->set('id', $id);
}
$setting = $this->Server->getSettingData($setting_name);
if ($this->request->is('get')) {
if ($setting != null) {
@ -1568,6 +1572,23 @@ class ServersController extends AppController
{
App::uses('SyncTool', 'Tools');
$params = array();
$this->loadModel('RestClientHistory');
$this->RestClientHistory->create();
$date = new DateTime();
$rest_history_item = array(
'org_id' => $this->Auth->user('org_id'),
'user_id' => $this->Auth->user('id'),
'headers' => $request['header'],
'body' => empty($request['body']) ? '' : $request['body'],
'url' => $request['url'],
'http_method' => $request['method'],
'use_full_path' => $request['use_full_path'],
'show_result' => $request['show_result'],
'skip_ssl' => $request['skip_ssl_validation'],
'bookmark' => $request['bookmark'],
'bookmark_name' => $request['name'],
'timestamp' => $date->getTimestamp()
);
if (!empty($request['url'])) {
if (empty($request['use_full_path'])) {
$path = preg_replace('#^(://|[^/?])+#', '', $request['url']);
@ -1581,6 +1602,8 @@ class ServersController extends AppController
}
if (!empty($request['skip_ssl_validation'])) {
$params['ssl_verify_peer'] = false;
$params['ssl_verify_host'] = false;
$params['ssl_allow_self_signed'] = true;
}
$params['timeout'] = 300;
App::uses('HttpSocket', 'Network/Http');
@ -1638,6 +1661,9 @@ class ServersController extends AppController
$view_data['data'] = 'Something went wrong.';
}
}
$rest_history_item['outcome'] = $response->code;
$this->RestClientHistory->save($rest_history_item);
$this->RestClientHistory->cleanup($this->Auth->user('id'));
return $view_data;
}
@ -1678,7 +1704,7 @@ misp.direct_call(relative_path, body)
$request['header']['Authorization'],
$verifyCert,
$relative,
(empty($request['body']) ? 'Null' : '\'' . $request['body'] . '\'')
(empty($request['body']) ? 'Null' : $request['body'])
);
return $python_script;
}

View File

@ -68,6 +68,7 @@ class ShadowAttributesController extends AppController
if (empty($shadow)) {
return array('false' => true, 'errors' => 'Proposal not found or you are not authorised to accept it.');
}
$this->ShadowAttribute->publishKafkaNotification('shadow_attribute', $shadow, 'accept');
$shadow = $shadow['ShadowAttribute'];
if ($this->ShadowAttribute->typeIsAttachment($shadow['type'])) {
$encodedFile = $this->ShadowAttribute->base64EncodeAttachment($shadow);
@ -229,6 +230,7 @@ class ShadowAttributesController extends AppController
if (empty($sa)) {
return false;
}
$this->ShadowAttribute->publishKafkaNotification('shadow_attribute', $sa, 'discard');
$eventId = $sa['ShadowAttribute']['event_id'];
$this->loadModel('Event');
$this->Event->Behaviors->detach('SysLogLogable.SysLogLogable');

View File

@ -227,9 +227,6 @@ class TagCollectionsController extends AppController
public function addTag($id = false, $tag_id = false)
{
if (!$this->request->is('post')) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
$rearrangeRules = array(
'request' => false,
'TagCollection' => false,
@ -242,102 +239,110 @@ class TagCollectionsController extends AppController
if ($id === false) {
$id = $this->request->data['tag_collection'];
}
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
}
if (!is_numeric($tag_id)) {
$tag_ids = json_decode($tag_id);
$tag_lookups = array();
foreach ($tag_ids as $temp) {
if (is_numeric($temp)) {
$tag_lookups['OR']['Tag.id'][] = $temp;
} else {
$tag_lookups['OR']['LOWER(Tag.name) LIKE'][] = strtolower(trim($tag_id));
}
}
if ($tag_ids !== null && is_array($tag_ids)) { // can decode json
$tag_ids = $this->TagCollection->TagCollectionTag->Tag->find('list', array(
'conditions' => array(
'AND' => array(
$conditions,
$tag_lookups
)
),
'fields' => array('Tag.id', 'Tag.id')
));
$tag_id_list = array_values($tag_ids);
if (empty($tag_id_list)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag(s).')), 'status'=>200, 'type' => 'json'));
}
} else {
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array('TagCollection.id' => $id)
));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid tag collection.')), 'status'=>200, 'type' => 'json'));
}
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $tagCollection['TagCollection']['org_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
}
$this->autoRender = false;
$error = false;
$success = false;
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
foreach ($tag_id_list as $tag_id) {
$this->TagCollection->TagCollectionTag->Tag->id = $tag_id;
if (!$this->TagCollection->TagCollectionTag->Tag->exists()) {
$error = __('Invalid Tag.');
continue;
}
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->TagCollection->TagCollectionTag->find('first', array(
'conditions' => array(
'tag_collection_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
if (!empty($found)) {
$error = __('Tag is already attached to this event.');
continue;
}
$this->TagCollection->TagCollectionTag->create();
if ($this->TagCollection->TagCollectionTag->save(array('tag_collection_id' => $id, 'tag_id' => $tag_id))) {
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'TagCollection', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to collection (' . $id . ')', 'Event (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success = __('Tag(s) added.');
} else {
$fail = __('Tag(s) could not be added.');
}
}
if ($success) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $success)), 'status'=>200, 'type' => 'json'));
} elseif (empty($fail)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('All tags are already present, nothing to add.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
if (!$this->request->is('post')) {
$this->set('object_id', $id);
$this->set('scope', 'TagCollection');
$this->layout = false;
$this->autoRender = false;
$this->render('/Events/add_tag');
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $fail)), 'status'=>200, 'type' => 'json'));
if ($tag_id === false) {
$tag_id = $this->request->data['tag'];
}
$conditions = array();
if (!$this->_isSiteAdmin()) {
$conditions['Tag.org_id'] = array('0', $this->Auth->user('org_id'));
$conditions['Tag.user_id'] = array('0', $this->Auth->user('id'));
}
if (!is_numeric($tag_id)) {
$tag_ids = json_decode($tag_id);
$tag_lookups = array();
foreach ($tag_ids as $temp) {
if (is_numeric($temp)) {
$tag_lookups['OR']['Tag.id'][] = $temp;
} else {
$tag_lookups['OR']['LOWER(Tag.name) LIKE'][] = strtolower(trim($tag_id));
}
}
if ($tag_ids !== null && is_array($tag_ids)) { // can decode json
$tag_ids = $this->TagCollection->TagCollectionTag->Tag->find('list', array(
'conditions' => array(
'AND' => array(
$conditions,
$tag_lookups
)
),
'fields' => array('Tag.id', 'Tag.id')
));
$tag_id_list = array_values($tag_ids);
if (empty($tag_id_list)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag(s).')), 'status'=>200, 'type' => 'json'));
}
} else {
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array('recursive' => -1, 'conditions' => $conditions));
if (empty($tag)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid Tag.')), 'status'=>200, 'type' => 'json'));
}
$tag_id = $tag['Tag']['id'];
}
}
$tagCollection = $this->TagCollection->find('first', array(
'recursive' => -1,
'conditions' => array('TagCollection.id' => $id)
));
if (empty($tagCollection)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'Invalid tag collection.')), 'status'=>200, 'type' => 'json'));
}
if (!$this->_isSiteAdmin()) {
if (!$this->userRole['perm_tagger'] || ($this->Auth->user('org_id') !== $tagCollection['TagCollection']['org_id'])) {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => 'You don\'t have permission to do that.')), 'status'=>200, 'type' => 'json'));
}
}
$this->autoRender = false;
$error = false;
$success = false;
if (empty($tag_id_list)) {
$tag_id_list = array($tag_id);
}
foreach ($tag_id_list as $tag_id) {
$this->TagCollection->TagCollectionTag->Tag->id = $tag_id;
if (!$this->TagCollection->TagCollectionTag->Tag->exists()) {
$error = __('Invalid Tag.');
continue;
}
$tag = $this->TagCollection->TagCollectionTag->Tag->find('first', array(
'conditions' => array('Tag.id' => $tag_id),
'recursive' => -1,
'fields' => array('Tag.name')
));
$found = $this->TagCollection->TagCollectionTag->find('first', array(
'conditions' => array(
'tag_collection_id' => $id,
'tag_id' => $tag_id
),
'recursive' => -1,
));
if (!empty($found)) {
$error = __('Tag is already attached to this event.');
continue;
}
$this->TagCollection->TagCollectionTag->create();
if ($this->TagCollection->TagCollectionTag->save(array('tag_collection_id' => $id, 'tag_id' => $tag_id))) {
$log = ClassRegistry::init('Log');
$log->createLogEntry($this->Auth->user(), 'tag', 'TagCollection', $id, 'Attached tag (' . $tag_id . ') "' . $tag['Tag']['name'] . '" to collection (' . $id . ')', 'Event (' . $id . ') tagged as Tag (' . $tag_id . ')');
$success = __('Tag(s) added.');
} else {
$fail = __('Tag(s) could not be added.');
}
}
if ($success) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $success)), 'status'=>200, 'type' => 'json'));
} elseif (empty($fail)) {
return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => __('All tags are already present, nothing to add.'), 'check_publish' => true)), 'status'=>200, 'type' => 'json'));
} else {
return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => $fail)), 'status'=>200, 'type' => 'json'));
}
}
}

View File

@ -476,6 +476,7 @@ class TagsController extends AppController
'fields' => array('Event.id', 'Event.orgc_id', 'Event.org_id', 'Event.user_id'),
'conditions' => array('Event.id' => $id)
));
$this->set('required_taxonomies', $this->EventTag->Event->getRequiredTaxonomies());
$this->set('event', $event);
$this->layout = 'ajax';
$this->render('/Events/ajax/ajaxTags');

View File

@ -54,10 +54,24 @@ class TaxonomiesController extends AppController
$filter = isset($this->passedArgs['filter']) ? $this->passedArgs['filter'] : false;
$taxonomy = $this->Taxonomy->getTaxonomy($id, array('full' => true, 'filter' => $filter));
if (empty($taxonomy)) {
throw new NotFoundException('Taxonomy not found.');
throw new NotFoundException(__('Taxonomy not found.'));
}
$this->loadModel('EventTag');
$this->loadModel('AttributeTag');
foreach ($taxonomy['entries'] as $key => $value) {
$taxonomy['entries'][$key]['events'] = empty($value['existing_tag']) ? 0 : count($value['existing_tag']['EventTag']);
$count = 0;
if (!empty($value['existing_tag'])) {
foreach ($value['existing_tag'] as $et) {
$count = $this->EventTag->find('count', array(
'conditions' => array('EventTag.tag_id' => $et['id'])
));
$count_a = $this->AttributeTag->find('count', array(
'conditions' => array('AttributeTag.tag_id' => $et['id'])
));
}
}
$taxonomy['entries'][$key]['events'] = $count;
$taxonomy['entries'][$key]['attributes'] = $count_a;
}
$this->set('filter', $filter);
$customPagination = new CustomPaginationTool();
@ -82,7 +96,7 @@ 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.');
throw new MethodNotAllowedException(__('You don\'t have permission to do that.'));
}
$taxonomy = $this->Taxonomy->find('first', array(
'recursive' => -1,
@ -105,7 +119,7 @@ class TaxonomiesController extends AppController
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Taxonomy', 'enable', $id, $this->response->type());
} else {
$this->Flash->success('Taxonomy enabled.');
$this->Flash->success(__('Taxonomy enabled.'));
$this->redirect($this->referer());
}
}
@ -113,7 +127,7 @@ 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.');
throw new MethodNotAllowedException(__('You don\'t have permission to do that.'));
}
$taxonomy = $this->Taxonomy->find('first', array(
'recursive' => -1,
@ -137,7 +151,7 @@ class TaxonomiesController extends AppController
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('Taxonomy', 'disable', $id, $this->response->type());
} else {
$this->Flash->success('Taxonomy disabled.');
$this->Flash->success(__('Taxonomy disabled.'));
$this->redirect($this->referer());
}
}
@ -145,7 +159,7 @@ class TaxonomiesController extends AppController
public function update()
{
if (!$this->_isSiteAdmin()) {
throw new MethodNotAllowedException('You don\'t have permission to do that.');
throw new MethodNotAllowedException(__('You don\'t have permission to do that.'));
}
$result = $this->Taxonomy->update();
$this->Log = ClassRegistry::init('Log');
@ -205,15 +219,15 @@ class TaxonomiesController extends AppController
$message = '';
if ($successes == 0 && $fails == 0) {
$flashType = 'info';
$message = 'All taxonomy libraries are up to date already.';
$message = __('All taxonomy libraries are up to date already.');
} elseif ($successes == 0) {
$flashType = 'error';
$message = 'Could not update any of the taxonomy libraries';
$message = __('Could not update any of the taxonomy libraries');
} else {
$flashType = 'success';
$message = 'Successfully updated ' . $successes . ' taxonomy libraries.';
$message = __('Successfully updated ') . $successes . __(' taxonomy libraries.');
if ($fails != 0) {
$message .= ' However, could not update ' . $fails . ' taxonomy libraries.';
$message .= __(' However, could not update ') . $fails . __(' taxonomy libraries.');
}
}
if ($this->_isRest()) {
@ -227,7 +241,7 @@ class TaxonomiesController extends AppController
public function addTag($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.');
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
if ($taxonomy_id) {
$result = $this->Taxonomy->addTags($taxonomy_id);
@ -247,9 +261,69 @@ class TaxonomiesController extends AppController
$result = $this->Taxonomy->addTags($this->request->data['Tag']['taxonomy_id'], $this->request->data['Tag']['nameList']);
}
if ($result) {
$this->Flash->success('The tag(s) has been saved.');
$this->Flash->success(__('The tag(s) has been saved.'));
} else {
$this->Flash->error('The tag(s) could not be saved. Please, try again.');
$this->Flash->error(__('The tag(s) could not be saved. Please, try again.'));
}
$this->redirect($this->referer());
}
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.'));
}
if ($taxonomy_id) {
$result = $this->Taxonomy->hideTags($taxonomy_id);
} else {
if (isset($this->request->data['Taxonomy'])) {
$this->request->data['Tag'] = $this->request->data['Taxonomy'];
unset($this->request->data['Taxonomy']);
}
if (isset($this->request->data['Tag']['request'])) {
$this->request->data['Tag'] = $this->request->data['Tag']['request'];
}
if (!isset($this->request->data['Tag']['nameList'])) {
$this->request->data['Tag']['nameList'] = array($this->request->data['Tag']['name']);
} else {
$this->request->data['Tag']['nameList'] = json_decode($this->request->data['Tag']['nameList'], true);
}
$result = $this->Taxonomy->hideTags($this->request->data['Tag']['taxonomy_id'], $this->request->data['Tag']['nameList']);
}
if ($result) {
$this->Flash->success(__('The tag(s) has been saved.'));
} else {
$this->Flash->error(__('The tag(s) could not be saved. Please, try again.'));
}
$this->redirect($this->referer());
}
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.'));
}
if ($taxonomy_id) {
$result = $this->Taxonomy->unhideTags($taxonomy_id);
} else {
if (isset($this->request->data['Taxonomy'])) {
$this->request->data['Tag'] = $this->request->data['Taxonomy'];
unset($this->request->data['Taxonomy']);
}
if (isset($this->request->data['Tag']['request'])) {
$this->request->data['Tag'] = $this->request->data['Tag']['request'];
}
if (!isset($this->request->data['Tag']['nameList'])) {
$this->request->data['Tag']['nameList'] = array($this->request->data['Tag']['name']);
} else {
$this->request->data['Tag']['nameList'] = json_decode($this->request->data['Tag']['nameList'], true);
}
$result = $this->Taxonomy->unhideTags($this->request->data['Tag']['taxonomy_id'], $this->request->data['Tag']['nameList']);
}
if ($result) {
$this->Flash->success(__('The tag(s) has been saved.'));
} else {
$this->Flash->error(__('The tag(s) could not be saved. Please, try again.'));
}
$this->redirect($this->referer());
}
@ -257,7 +331,7 @@ class TaxonomiesController extends AppController
public function disableTag($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.');
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
if ($taxonomy_id) {
$result = $this->Taxonomy->disableTags($taxonomy_id);
@ -277,9 +351,9 @@ class TaxonomiesController extends AppController
$result = $this->Taxonomy->disableTags($this->request->data['Tag']['taxonomy_id'], $this->request->data['Tag']['nameList']);
}
if ($result) {
$this->Flash->success('The tag(s) has been hidden.');
$this->Flash->success(__('The tag(s) has been hidden.'));
} else {
$this->Flash->error('The tag(s) could not be hidden. Please, try again.');
$this->Flash->error(__('The tag(s) could not be hidden. Please, try again.'));
}
$this->redirect($this->referer());
}
@ -287,21 +361,39 @@ class TaxonomiesController extends AppController
public function taxonomyMassConfirmation($id)
{
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) {
throw new NotFoundException('You don\'t have permission to do that.');
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
$this->set('id', $id);
$this->render('ajax/taxonomy_mass_confirmation');
}
public function taxonomyMassHide($id)
{
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
$this->set('id', $id);
$this->render('ajax/taxonomy_mass_hide');
}
public function taxonomyMassUnhide($id)
{
if (!$this->_isSiteAdmin() && !$this->userRole['perm_tagger']) {
throw new NotFoundException(__('You don\'t have permission to do that.'));
}
$this->set('id', $id);
$this->render('ajax/taxonomy_mass_unhide');
}
public function delete($id)
{
if ($this->request->is('post')) {
$result = $this->Taxonomy->delete($id, true);
if ($result) {
$this->Flash->success('Taxonomy successfuly deleted.');
$this->Flash->success(__('Taxonomy successfuly deleted.'));
$this->redirect(array('controller' => 'taxonomies', 'action' => 'index'));
} else {
$this->Flash->error('Taxonomy could not be deleted.');
$this->Flash->error(__('Taxonomy could not be deleted.'));
$this->redirect(array('controller' => 'taxonomies', 'action' => 'index'));
}
} else {
@ -309,8 +401,34 @@ class TaxonomiesController extends AppController
$this->set('id', $id);
$this->render('ajax/taxonomy_delete_confirmation');
} else {
throw new MethodNotAllowedException('This function can only be reached via AJAX.');
throw new MethodNotAllowedException(__('This function can only be reached via AJAX.'));
}
}
}
public function toggleRequired($id)
{
$taxonomy = $this->Taxonomy->find('first', array(
'recursive' => -1,
'conditions' => array('Taxonomy.id' => $id)
));
if (empty($taxonomy)) {
return $this->RestResponse->saveFailResponse('Taxonomy', 'toggleRequired', $id, 'Invalid Taxonomy', $this->response->type());
}
if ($this->request->is('post')) {
$taxonomy['Taxonomy']['required'] = $this->request->data['Taxonomy']['required'];
$result = $this->Taxonomy->save($taxonomy);
if ($result) {
return $this->RestResponse->saveSuccessResponse('Taxonomy', 'toggleRequired', $id, $this->response->type());
} else {
return $this->RestResponse->saveFailResponse('Taxonomy', 'toggleRequired', $id, $this->validationError, $this->response->type());
}
} else {
$this->set('required', !$taxonomy['Taxonomy']['required']);
$this->set('id', $id);
$this->autoRender = false;
$this->layout = 'ajax';
$this->render('ajax/toggle_required');
}
}
}

View File

@ -173,37 +173,63 @@ class UsersController extends AppController
'recursive' => -1
));
if ($this->request->is('post') || $this->request->is('put')) {
if (!isset($this->request->data['User'])) {
$this->request->data = array('User' => $this->request->data);
}
$abortPost = false;
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']);
if (!$hashed) {
$message = __('Invalid password. Please enter your current password to continue.');
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Users', 'change_pw', false, $message, $this->response->type());
}
$abortPost = true;
$this->Flash->error('Invalid password. Please enter your current password to continue.');
$this->Flash->error($message);
}
unset($this->request->data['User']['current_password']);
} else {
} else if (!$this->_isRest()) {
$message = __('Please enter your current password to continue.');
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Users', 'change_pw', false, $message, $this->response->type());
}
$abortPost = true;
$this->Flash->info('Please enter your current password to continue.');
$this->Flash->info($message);
}
}
if (!$abortPost) {
// What fields should be saved (allowed to be saved)
$user['User']['change_pw'] = 0;
$user['User']['password'] = $this->request->data['User']['password'];
$user['User']['confirm_password'] = $this->request->data['User']['confirm_password'];
if ($this->_isRest()) {
$user['User']['confirm_password'] = $this->request->data['User']['password'];
} else {
$user['User']['confirm_password'] = $this->request->data['User']['confirm_password'];
}
$temp = $user['User']['password'];
// Save the data
if ($this->User->save($user)) {
$this->Flash->success(__('Password Changed.'));
$this->_refreshAuth();
$message = __('Password Changed.');
$this->__extralog("change_pw");
if ($this->_isRest()) {
return $this->RestResponse->saveSuccessResponse('User', 'change_pw', false, $this->response->type(), $message);
}
$this->Flash->success($message);
$this->_refreshAuth();
$this->redirect(array('action' => 'view', $id));
} else {
$this->Flash->error(__('The password could not be updated. Make sure you meet the minimum password length / complexity requirements.'));
$message = __('The password could not be updated. Make sure you meet the minimum password length / complexity requirements.');
if ($this->_isRest()) {
return $this->RestResponse->saveFailResponse('Users', 'change_pw', false, $message, $this->response->type());
}
$this->Flash->error($message);
}
}
}
if ($this->_isRest()) {
return $this->RestResponse->describe('Users', 'change_pw', false, $this->response->type());
}
$this->loadModel('Server');
$this->set('complexity', !empty(Configure::read('Security.password_policy_complexity')) ? Configure::read('Security.password_policy_complexity') : $this->Server->serverSettings['Security']['password_policy_complexity']['value']);
$this->set('length', !empty(Configure::read('Security.password_policy_length')) ? Configure::read('Security.password_policy_length') : $this->Server->serverSettings['Security']['password_policy_length']['value']);
@ -1122,7 +1148,7 @@ class UsersController extends AppController
$this->_refreshAuth();
$this->redirect($this->referer());
} else {
return $this->RestResponse->saveSuccessResponse('User', 'resetauthkey', $id, $this->response->type(), 'User\'s authkey has been reset.');
return $this->RestResponse->saveSuccessResponse('User', 'resetauthkey', $id, $this->response->type(), 'Authkey updated: ' . $newkey);
}
}
@ -1256,7 +1282,7 @@ class UsersController extends AppController
} elseif ($action == 'edit') {
$description = "User (" . $this->User->id . "): " . $this->data['User']['email'];
} elseif ($action == 'change_pw') {
$description = "User (" . $this->User->id . "): " . $this->data['User']['email'];
$description = "User (" . $this->User->id . "): " . $this->Auth->user('email');
$fieldsResult = "Password changed.";
}
@ -1527,7 +1553,7 @@ class UsersController extends AppController
public function statistics($page = 'data')
{
$this->set('page', $page);
$pages = array('data' => 'Usage data', 'orgs' => 'Organisations', 'users' => 'User and Organisation statistics', 'tags' => 'Tags', 'attributehistogram' => 'Attribute histogram', 'sightings' => 'Sightings toplists', 'attackMatrix' => 'ATT&CK Matrix');
$pages = array('data' => 'Usage data', 'orgs' => 'Organisations', 'users' => 'User and Organisation statistics', 'tags' => 'Tags', 'attributehistogram' => 'Attribute histogram', 'sightings' => 'Sightings toplists', 'galaxyMatrix' => 'Galaxy Matrix');
if (!$this->_isSiteAdmin() && !empty(Configure::read('Security.hide_organisation_index_from_users'))) {
unset($pages['orgs']);
}
@ -1552,8 +1578,8 @@ class UsersController extends AppController
}
} elseif ($page == 'sightings') {
$result = $this->__statisticsSightings($this->params['named']);
} elseif ($page == 'attackMatrix') {
$result = $this->__statisticsAttackMatrix($this->params['named']);
} elseif ($page == 'galaxyMatrix') {
$result = $this->__statisticsGalaxyMatrix($this->params['named']);
}
if ($this->_isRest()) {
return $result;
@ -1855,12 +1881,16 @@ class UsersController extends AppController
}
}
private function __statisticsAttackMatrix($params = array())
private function __statisticsGalaxyMatrix($params = array())
{
$this->loadModel('Event');
$this->loadModel('Galaxy');
$galaxy_id = $this->Galaxy->getMitreAttackGalaxyId();
$mitre_galaxy_id = $this->Galaxy->getMitreAttackGalaxyId();
if (isset($params['galaxy_id'])) {
$galaxy_id = $params['galaxy_id'];
} else {
$galaxy_id = $mitre_galaxy_id;
}
$matrixData = $this->Galaxy->getMatrix($galaxy_id);
$tabs = $matrixData['tabs'];
@ -1877,7 +1907,7 @@ class UsersController extends AppController
$maxScore = max($scoresDataAttr['maxScore'], $scoresDataEvent['maxScore']);
$scores = $scoresData;
// FIXME: temporary fix: add the score of deprecated mitre galaxies to the new one (for the stats)
if ($matrixData['galaxy']['id'] == $galaxy_id) {
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
$mergedScore = array();
foreach ($scoresData as $tag => $v) {
$predicateValue = explode(':', $tag, 2)[1];
@ -1937,10 +1967,17 @@ class UsersController extends AppController
$this->set('interpolation', $colours['interpolation']);
}
$this->set('pickingMode', false);
$this->set('defaultTabName', "mitre-attack");
if ($matrixData['galaxy']['id'] == $mitre_galaxy_id) {
$this->set('defaultTabName', "mitre-attack");
}
$this->set('removeTrailling', 2);
$this->render('statistics_attackmatrix');
$this->set('galaxyName', $matrixData['galaxy']['name']);
$this->set('galaxyId', $matrixData['galaxy']['id']);
$matrixGalaxies = $this->Galaxy->getAllowedMatrixGalaxies();
$this->set('matrixGalaxies', $matrixGalaxies);
$this->render('statistics_galaxymatrix');
}
}

View File

@ -162,8 +162,8 @@ class BroExport
$orgName = $instanceString . ' (' . $item['Event']['uuid'] . ')' . ' - ' . $orgs[$item['Event']['orgc_id']];
}
$ruleFormatReference = Configure::read('MISP.baseurl') . '/events/view/' . $item['Event']['id'];
$ruleFormat = "%s\t%s\t" . $orgName . "\t" . $this->replaceIllegalChars($item['Event']['info']) . ". %s" . "\t" . $ruleFormatReference . "\t%s\t%s";
$rule = $this->__generateRule($item['Attribute'], $ruleFormat, $valueField, $whitelist);
$ruleFormat = "%s\t%s\t" . $orgName . "\t%s. %s\t" . $ruleFormatReference . "\t%s\t%s";
$rule = $this->__generateRule($item, $ruleFormat, $valueField, $whitelist);
if (!empty($rule)) {
$intel[] = $rule;
}
@ -171,32 +171,33 @@ class BroExport
return $intel;
}
private function __generateRule($attribute, $ruleFormat, $valueField, $whitelist = array())
private function __generateRule($item, $ruleFormat, $valueField, $whitelist = array())
{
if (isset($this->mapping[$attribute['type']])) {
if (empty($whitelist) || !$this->checkWhitelist($attribute['value'], $whitelist)) {
$brotype = $this->mapping[$attribute['type']]['brotype'];
if (isset($this->mapping[$attribute['type']]['alternate'])) {
if (preg_match($this->mapping[$attribute['type']]['alternate'][0], $attribute['value'])) {
$brotype = $this->mapping[$attribute['type']]['alternate'][1];
if (isset($this->mapping[$item['Attribute']['type']])) {
if (empty($whitelist) || !$this->checkWhitelist($item['Attribute']['value' . $valueField], $whitelist)) {
$brotype = $this->mapping[$item['Attribute']['type']]['brotype'];
if (isset($this->mapping[$item['Attribute']['type']]['alternate'])) {
if (preg_match($this->mapping[$item['Attribute']['type']]['alternate'][0], $item['Attribute']['value' . $valueField])) {
$brotype = $this->mapping[$item['Attribute']['type']]['alternate'][1];
}
}
if ($valueField == 2 && isset($this->mapping[$attribute['type']]['composite'])) {
$brotype = $this->mapping[$attribute['type']]['composite'];
if ($valueField == 2 && isset($this->mapping[$item['Attribute']['type']]['composite'])) {
$brotype = $this->mapping[$item['Attribute']['type']]['composite'];
}
$attribute['value'] = $this->replaceIllegalChars($attribute['value']); // substitute chars not allowed in rule
if (isset($this->mapping[$attribute['type']]['replace'])) {
$attribute['value'] = preg_replace(
$this->mapping[$attribute['type']]['replace'][0],
$this->mapping[$attribute['type']]['replace'][1],
$attribute['value']
$item['Attribute']['value' . $valueField] = $this->replaceIllegalChars($item['Attribute']['value' . $valueField]); // substitute chars not allowed in rule
if (isset($this->mapping[$item['Attribute']['type']]['replace'])) {
$item['Attribute']['value' . $valueField] = preg_replace(
$this->mapping[$item['Attribute']['type']]['replace'][0],
$this->mapping[$item['Attribute']['type']]['replace'][1],
$item['Attribute']['value' . $valueField]
);
}
return sprintf(
$ruleFormat,
$this->replaceIllegalChars($attribute['value']), // value - for composite values only the relevant element is taken
$this->replaceIllegalChars($item['Attribute']['value' . $valueField]), // value - for composite values only the relevant element is taken
'Intel::' . $brotype, // type
$this->replaceIllegalChars($attribute['comment']),
$this->replaceIllegalChars($item['Event']['info']),
$this->replaceIllegalChars($item['Attribute']['comment']),
'T', // meta.do_notice
'-' // meta.if_in
);

View File

@ -169,6 +169,7 @@ class RPZExport
public function buildHeader($rpzSettings)
{
$rpzSettings['serial'] = str_replace('$date', date('Ymd'), $rpzSettings['serial']);
$rpzSettings['serial'] = str_replace('$time', time(), $rpzSettings['serial']);
$header = '';
$header .= '$TTL ' . $rpzSettings['ttl'] . ';' . PHP_EOL;
$header .= '@ SOA ' . $rpzSettings['ns'] . ' ' . $rpzSettings['email'] . ' (' . $rpzSettings['serial'] . ' ' . $rpzSettings['refresh'] . ' ' . $rpzSettings['retry'] . ' ' . $rpzSettings['expiry'] . ' ' . $rpzSettings['minimum_ttl'] . ')' . PHP_EOL;

View File

@ -352,7 +352,7 @@ class ComplexTypeTool
// Phone numbers - for automatic recognition, needs to start with + or include dashes
if (!empty($input['raw'])) {
if ($input['raw'][0] === '+' || strpos($input['raw'], '-')) {
if (preg_match("#^(\+)?([0-9]{1,3}(\(0\))?)?[0-9\/\-]{5,}[0-9]$#i", $input['raw'])) {
if (!preg_match('#^[0-9]{4}-[0-9]{2}-[0-9]{2}$#i', $input['raw']) && preg_match("#^(\+)?([0-9]{1,3}(\(0\))?)?[0-9\/\-]{5,}[0-9]$#i", $input['raw'])) {
return array('types' => array('phone-number', 'prtn', 'whois-registrant-phone'), 'categories' => array('Other'), 'to_ids' => false, 'default_type' => 'phone-number', 'value' => $input['raw']);
}
}

View File

@ -16,8 +16,8 @@
// construct distribution info
$this->__json['distributionInfo'] = array();
$sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'name', 1);
$this->__json['allSharingGroup'] = h(array_values($sgs));
$sgs = $this->__eventModel->SharingGroup->fetchAllAuthorised($this->__user, 'simplified', 1);
$this->__json['allSharingGroup'] = h($sgs);
$distributionLevels = $this->__eventModel->distributionLevels;
foreach ($distributionLevels as $key => $value) {
$this->__json['distributionInfo'][$key] = array('key' => h($value), 'desc' => h($this->__eventModel->distributionDescriptions[$key]['formdesc']), 'value' => h($key));
@ -59,6 +59,12 @@
$this->__json['additionalDistributionInfo'][$distributionLevel] = array();
}
$this->__json['additionalDistributionInfo'][$distributionLevel][h($data)] = 0; // set-alike
if ($distributionLevel == 4) {
if (!isset($this->__json['sharingGroupRepartition'][h($data)])) {
$this->__json['sharingGroupRepartition'][h($data)] = 0;
}
$this->__json['sharingGroupRepartition'][h($data)]++;
}
}
private function __addOtherDistributionInfo()
@ -124,17 +130,28 @@
public function get_distributions_graph($id)
{
$event = $this->__get_event($id);
$eventDist = $event['distribution'];
$eventSGName = $event['SharingGroupName'];
$this->__eventDistribution = $eventDist;
$this->__eventSharingGroupName = $eventSGName;
$this->__json['event'] = $this->init_array_distri();
$this->__json['attribute'] = $this->init_array_distri();
$this->__json['object'] = $this->init_array_distri();
$this->__json['obj_attr'] = $this->init_array_distri();
$this->__json['additionalDistributionInfo'] = $this->init_array_distri(array());
$this->__json['sharingGroupRepartition'] = array();
$this->__addOtherDistributionInfo();
// transform set into array
foreach (array_keys($this->__json['additionalDistributionInfo']) as $d) {
$this->__json['additionalDistributionInfo'][$d] = array_keys($this->__json['additionalDistributionInfo'][$d]);
}
if ($id === -1) {
return $this->__json;
}
$event = $this->__get_event($id);
$eventDist = $event['distribution'];
$eventSGName = $event['SharingGroupName'];
$this->__eventDistribution = $eventDist;
$this->__eventSharingGroupName = $eventSGName;
if (empty($event)) {
return $this->__json;
@ -188,13 +205,8 @@
unset($this->__json['distributionInfo'][5]); // inherit event.
$this->__addOtherDistributionInfo();
// transform set into array
foreach (array_keys($this->__json['additionalDistributionInfo']) as $d) {
$this->__json['additionalDistributionInfo'][$d] = array_keys($this->__json['additionalDistributionInfo'][$d]);
}
// transform set into array for SG (others are already done)
$this->__json['additionalDistributionInfo'][4] = array_keys($this->__json['additionalDistributionInfo'][4]);
return $this->__json;
}

View File

@ -0,0 +1,55 @@
<?php
class KafkaPubTool
{
private $rdkafka = false;
private function __error($msg)
{
error_log($msg, 3, APP . 'tmp' . DS . 'logs' . DS . 'kafka.error.log');
}
public function initTool($brokers, $config)
{
if (!$this->rdkafka) {
try {
$rdConf = new RdKafka\Conf();
foreach ($config as $key => $val) {
if (!empty($val)) {
$rdConf->set($key, $val);
}
}
$rdConf->setErrorCb(function ($kafka, $err, $reason) {
$this->__error(sprintf("%s (reason: %s)\n", rd_kafka_err2str($err), $reason));
});
$rdkafka = new RdKafka\Producer($rdConf);
if ($rdkafka->addBrokers($brokers) == 0) {
$this->__error("Could not add any Kafka brokers");
}
$this->rdkafka = $rdkafka;
} catch (Exception $e) {
$this->__error('Exception: ' . $e->getMessage() . "\n");
}
}
}
public function publishJson($topicName, $data, $action = false)
{
try {
if (!empty($action)) {
$data['action'] = $action;
}
$body = json_encode($data);
if (!$body) {
$this->__error("Error encoding to JSON: ". $data);
}
if (!empty($this->rdkafka)) {
$topic = $this->rdkafka->newTopic($topicName);
$topic->produce(RD_KAFKA_PARTITION_UA, 0, $body);
$this->rdkafka->poll(0);
}
} catch (Exception $e) {
$this->__error('Exception: ' . $e->getMessage() . "\n");
}
}
}

@ -1 +1 @@
Subproject commit ab5578dbc9f88e661d2b017489cd156fca961429
Subproject commit c4a51509c554a0762e8b4d9b3985fe042b445fe7

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

0
app/Locale/fra/LC_MESSAGES/cake_dev.po Normal file → Executable file
View File

File diff suppressed because it is too large Load Diff

View File

@ -6624,6 +6624,10 @@ msgstr ""
msgid "Quickfilter"
msgstr ""
#: View/Events/index.ctp:95
msgid "Enter value to search"
msgstr ""
#: View/Events/index.ctp:44
#: View/Organisations/index.ctp:59
#: View/Servers/preview_index.ctp:45

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6624,6 +6624,10 @@ msgstr ""
msgid "Quickfilter"
msgstr ""
#: View/Events/index.ctp:95
msgid "Enter value to search"
msgstr ""
#: View/Events/index.ctp:44
#: View/Organisations/index.ctp:59
#: View/Servers/preview_index.ctp:45

File diff suppressed because it is too large Load Diff

View File

@ -30,6 +30,8 @@ class AppModel extends Model
public $loadedPubSubTool = false;
public $loadedKafkaPubTool = false;
public $start = 0;
public $inserted_ids = array();
@ -72,7 +74,8 @@ class AppModel extends Model
7 => false, 8 => false, 9 => false, 10 => false, 11 => false, 12 => false,
13 => false, 14 => false, 15 => false, 18 => false, 19 => false, 20 => false,
21 => false, 22 => false, 23 => false, 24 => false, 25 => false, 26 => false,
27 => false, 28 => false, 29 => false, 30 => false
27 => false, 28 => false, 29 => false, 30 => false, 31 => false, 32 => false,
33 => false
);
public function afterSave($created, $options = array())
@ -1096,6 +1099,34 @@ class AppModel extends Model
$sqlArray[] = "ALTER TABLE `galaxies` MODIFY COLUMN `kill_chain_order` text";
$sqlArray[] = "ALTER TABLE `feeds` ADD `force_to_ids` tinyint(1) NOT NULL DEFAULT 0;";
break;
case 31:
$sqlArray[] = "CREATE TABLE IF NOT EXISTS `rest_client_histories` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`org_id` int(11) NOT NULL,
`user_id` int(11) NOT NULL,
`headers` text,
`body` text,
`url` text,
`http_method` varchar(255),
`timestamp` int(11) NOT NULL DEFAULT 0,
`use_full_path` tinyint(1) DEFAULT 0,
`show_result` tinyint(1) DEFAULT 0,
`skip_ssl` tinyint(1) DEFAULT 0,
`outcome` int(11) NOT NULL,
`bookmark` tinyint(1) NOT NULL DEFAUlT 0,
`bookmark_name` varchar(255) NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `org_id` (`org_id`),
KEY `user_id` (`user_id`),
KEY `timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;";
break;
case 32:
$sqlArray[] = "ALTER TABLE `taxonomies` ADD `required` tinyint(1) NOT NULL DEFAULT 0;";
break;
case 33:
$sqlArray[] = "ALTER TABLE `roles` ADD `perm_publish_kafka` tinyint(1) NOT NULL DEFAULT 0;";
break;
case 'fixNonEmptySharingGroupID':
$sqlArray[] = 'UPDATE `events` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
$sqlArray[] = 'UPDATE `attributes` SET `sharing_group_id` = 0 WHERE `distribution` != 4;';
@ -1506,6 +1537,36 @@ class AppModel extends Model
return $redis;
}
public function getKafkaPubTool()
{
if (!$this->loadedKafkaPubTool) {
$this->loadKafkaPubTool();
}
return $this->loadedKafkaPubTool;
}
public function loadKafkaPubTool()
{
App::uses('KafkaPubTool', 'Tools');
$kafkaPubTool = new KafkaPubTool();
$rdkafkaIni = Configure::read('Plugin.Kafka_rdkafka_config');
$kafkaConf = array();
if (!empty($rdkafkaIni)) {
$kafkaConf = parse_ini_file($rdkafkaIni);
}
$brokers = Configure::read('Plugin.Kafka_brokers');
$kafkaPubTool->initTool($brokers, $kafkaConf);
$this->loadedKafkaPubTool = $kafkaPubTool;
return true;
}
public function publishKafkaNotification($topicName, $data, $action = false) {
$kafkaTopic = Configure::read('Plugin.Kafka_' . $topicName . '_notifications_topic');
if (Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_' . $topicName . '_notifications_enable') && !empty($kafkaTopic)) {
$this->getKafkaPubTool()->publishJson($kafkaTopic, $data, $action);
}
}
public function getPubSubTool()
{
if (!$this->loadedPubSubTool) {

View File

@ -645,8 +645,10 @@ class Attribute extends AppModel
if (isset($this->data['Attribute']['type']) && $this->typeIsAttachment($this->data['Attribute']['type']) && !empty($this->data['Attribute']['data'])) {
$result = $result && $this->saveBase64EncodedAttachment($this->data['Attribute']); // TODO : is this correct?
}
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_attribute_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_attribute_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_attribute_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_attribute_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$attribute = $this->fetchAttribute($this->id);
if (!empty($attribute)) {
$user = array(
@ -663,10 +665,21 @@ class Attribute extends AppModel
if (!empty($this->data['Attribute']['deleted'])) {
$action = 'soft-delete';
}
if (Configure::read('Plugin.ZeroMQ_include_attachments') && $this->typeIsAttachment($attribute['Attribute']['type'])) {
$attribute['Attribute']['data'] = $this->base64EncodeAttachment($attribute['Attribute']);
if ($pubToZmq) {
if (Configure::read('Plugin.ZeroMQ_include_attachments') && $this->typeIsAttachment($attribute['Attribute']['type'])) {
$attribute['Attribute']['data'] = $this->base64EncodeAttachment($attribute['Attribute']);
}
$pubSubTool = $this->getPubSubTool();
$pubSubTool->attribute_save($attribute, $action);
unset($attribute['Attribute']['data']);
}
if ($pubToKafka) {
if (Configure::read('Plugin.Kafka_include_attachments') && $this->typeIsAttachment($attribute['Attribute']['type'])) {
$attribute['Attribute']['data'] = $this->base64EncodeAttachment($attribute['Attribute']);
}
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $attribute, $action);
}
$pubSubTool->attribute_save($attribute, $action);
}
}
if (Configure::read('MISP.enable_advanced_correlations') && in_array($this->data['Attribute']['type'], array('ip-src', 'ip-dst', 'domain-ip')) && strpos($this->data['Attribute']['value'], '/')) {
@ -712,6 +725,11 @@ class Attribute extends AppModel
$pubSubTool = $this->getPubSubTool();
$pubSubTool->attribute_save($this->data, 'delete');
}
$kafkaTopic = Configure::read('Plugin.Kafka_attribute_notifications_topic');
if (Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_attribute_notifications_enable') && !empty($kafkaTopic)) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $this->data, 'delete');
}
}
}
@ -2390,7 +2408,7 @@ class Attribute extends AppModel
'conditions' => $conditions, // array of conditions
'order' => 'Attribute.value' . $valueField . ' ASC',
'recursive' => -1, // int
'fields' => array('Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.comment', 'Attribute.value' . $valueField . " as value"),
'fields' => array('Attribute.id', 'Attribute.event_id', 'Attribute.type', 'Attribute.category', 'Attribute.comment', 'Attribute.to_ids', 'Attribute.value', 'Attribute.value' . $valueField),
'contain' => array('Event' => array('fields' => array('Event.id', 'Event.threat_level_id', 'Event.orgc_id', 'Event.uuid'))),
'group' => array('Attribute.type', 'Attribute.value' . $valueField), // fields to GROUP BY
'enforceWarninglist' => $enforceWarninglist
@ -2885,7 +2903,7 @@ class Attribute extends AppModel
)
)
),
'fields' => array('ShadowAttribute.id')
'fields' => array('ShadowAttribute.id', 'ShadowAttribute.value', 'ShadowAttribute.type', 'ShadowAttribute.category', 'ShadowAttribute.to_ids')
)
);
$params['contain'] = array_merge($params['contain'], $proposalRestriction);
@ -2999,7 +3017,7 @@ class Attribute extends AppModel
$results[$key]['Attribute']['event_uuid'] = $results[$key]['Event']['uuid'];
}
if ($proposals_block_attributes) {
$results = $this->__blockAttributeViaProposal($results, $key);
$this->__blockAttributeViaProposal($results, $key);
}
if ($options['withAttachments']) {
if ($this->typeIsAttachment($attribute['Attribute']['type'])) {
@ -3007,7 +3025,9 @@ class Attribute extends AppModel
$results[$key]['Attribute']['data'] = $encodedFile;
}
}
$attributes[] = $results[$key];
if (!empty($results[$key])) {
$attributes[] = $results[$key];
}
}
if (!empty($break)) {
break;
@ -3047,8 +3067,8 @@ class Attribute extends AppModel
if ($sa['value'] === $attributes[$k]['Attribute']['value'] &&
$sa['type'] === $attributes[$k]['Attribute']['type'] &&
$sa['category'] === $attributes[$k]['Attribute']['category'] &&
$sa['to_ids'] == 0 &&
$attribute['to_ids'] == 1
($sa['to_ids'] == 0 || $sa['to_ids'] == '') &&
$attributes[$k]['Attribute']['to_ids'] == 1
) {
unset($attributes[$k]);
}
@ -3056,7 +3076,6 @@ class Attribute extends AppModel
} else {
unset($attributes[$k]['ShadowAttribute']);
}
return $attributes;
}
// Method gets and converts the contents of a file passed along as a base64 encoded string with the original filename into a zip archive
@ -3194,13 +3213,7 @@ class Attribute extends AppModel
}
foreach ($attributes as $k => $attribute) {
if (!empty($attribute['encrypt']) && $attribute['encrypt']) {
if (strpos($attribute['value'], '|') !== false) {
$temp = explode('|', $attribute['value']);
$attribute['value'] = $temp[0];
}
$result = $this->handleMaliciousBase64($attribute['event_id'], $attribute['value'], $attribute['data'], array('md5'));
$attribute['data'] = $result['data'];
$attribute['value'] = $attribute['value'] . '|' . $result['md5'];
$attribute = $this->onDemandEncrypt($attribute);
}
if (!isset($attribute['distribution'])) {
$attribute['distribution'] = $defaultDistribution;
@ -3212,6 +3225,18 @@ class Attribute extends AppModel
return true;
}
public function onDemandEncrypt($attribute)
{
if (strpos($attribute['value'], '|') !== false) {
$temp = explode('|', $attribute['value']);
$attribute['value'] = $temp[0];
}
$result = $this->handleMaliciousBase64($attribute['event_id'], $attribute['value'], $attribute['data'], array('md5'));
$attribute['data'] = $result['data'];
$attribute['value'] = $attribute['value'] . '|' . $result['md5'];
return $attribute;
}
public function saveAndEncryptAttribute($attribute, $user = false)
{
$hashes = array('md5' => 'malware-sample', 'sha1' => 'filename|sha1', 'sha256' => 'filename|sha256');
@ -3580,6 +3605,9 @@ class Attribute extends AppModel
}
}
}
if (!empty($this->validationErrors)) {
$validationErrors = $this->validationErrors;
}
return $attribute;
}

View File

@ -30,8 +30,10 @@ class AttributeTag extends AppModel
public function afterSave($created, $options = array())
{
parent::afterSave($created, $options);
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('AttributeTag.id' => $this->id),
@ -40,15 +42,24 @@ class AttributeTag extends AppModel
$tag['Tag']['attribute_id'] = $tag['AttributeTag']['attribute_id'];
$tag['Tag']['event_id'] = $tag['AttributeTag']['event_id'];
$tag = array('Tag' => $tag['Tag']);
$pubSubTool->tag_save($tag, 'attached to attribute');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, 'attached to attribute');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, 'attached to attribute');
}
}
}
public function beforeDelete($cascade = true)
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
if (!empty($this->id)) {
$pubSubTool = $this->getPubSubTool();
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('AttributeTag.id' => $this->id),
@ -57,7 +68,14 @@ class AttributeTag extends AppModel
$tag['Tag']['attribute_id'] = $tag['AttributeTag']['attribute_id'];
$tag['Tag']['event_id'] = $tag['AttributeTag']['event_id'];
$tag = array('Tag' => $tag['Tag']);
$pubSubTool->tag_save($tag, 'detached from attribute');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, 'detached from attribute');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, 'detached from attribute');
}
}
}
}

View File

@ -354,10 +354,33 @@ class Event extends AppModel
$orgc = $this->Orgc->find('first', array('conditions' => array('Orgc.id' => $this->data['Event']['orgc_id']), 'recursive' => -1, 'fields' => array('Orgc.name')));
$this->EventBlacklist->save(array('event_uuid' => $this->data['Event']['uuid'], 'event_info' => $this->data['Event']['info'], 'event_orgc' => $orgc['Orgc']['name']));
if (!empty($this->data['Event']['id'])) {
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_attribute_notifications_enable')) {
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_event_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->event_save(array('Event' => $this->data['Event']), 'delete');
}
if (Configure::read('Plugin.Kafka_enable')) {
$kafkaEventTopic = Configure::read('Plugin.Kafka_event_notifications_topic');
if(Configure::read('Plugin.Kafka_event_notifications_enable') && !empty($kafkaEventTopic)) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaEventTopic, array('Event' => $this->data['Event']), 'delete');
}
$kafkaPubTopic = Configure::read('Plugin.Kafka_event_publish_notifications_topic');
if (!empty($this->data['Event']['published']) && Configure::read('Plugin.Kafka_event_publish_notifications_enable') && !empty($kafkaPubTopic)) {
$hostOrg = $this->Org->find('first', array('conditions' => array('name' => Configure::read('MISP.org')), 'fields' => array('id')));
if (!empty($hostOrg)) {
$user = array('org_id' => $hostOrg['Org']['id'], 'Role' => array('perm_sync' => 0, 'perm_audit' => 0, 'perm_site_admin' => 0), 'Organisation' => $hostOrg['Org']);
$params = array('eventid' => $this->data['Event']['id']);
if (Configure::read('Plugin.Kafka_include_attachments')) {
$params['includeAttachments'] = 1;
}
$fullEvent = $this->fetchEvent($user, $params);
if (!empty($fullEvent)) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaPubTopic, $fullEvent[0], 'delete');
}
}
}
}
}
}
@ -483,6 +506,9 @@ class Event extends AppModel
$pubSubTool->event_save($event, $created ? 'add' : 'edit');
}
}
if (empty($this->data['Event']['unpublishAction']) && empty($this->data['Event']['skip_kafka'])) {
$this->publishKafkaNotification('event', $this->quickFetchEvent($this->data['Event']['id']), $created ? 'add' : 'edit');
}
}
public function buildEventConditions($user)
@ -3874,20 +3900,37 @@ class Event extends AppModel
$event['Event']['published'] = 1;
$event['Event']['publish_timestamp'] = time();
$event['Event']['skip_zmq'] = 1;
$event['Event']['skip_kafka'] = 1;
$this->save($event, array('fieldList' => $fieldList));
}
if (Configure::read('Plugin.ZeroMQ_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_event_publish_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_event_publish_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$hostOrg = $this->Org->find('first', array('conditions' => array('name' => Configure::read('MISP.org')), 'fields' => array('id')));
if (!empty($hostOrg)) {
$user = array('org_id' => $hostOrg['Org']['id'], 'Role' => array('perm_sync' => 0, 'perm_audit' => 0, 'perm_site_admin' => 0), 'Organisation' => $hostOrg['Org']);
$params = array('eventid' => $id);
if (Configure::read('Plugin.ZeroMQ_include_attachments')) {
$params['includeAttachments'] = 1;
if ($pubToZmq) {
$params = array('eventid' => $id);
if (Configure::read('Plugin.ZeroMQ_include_attachments')) {
$params['includeAttachments'] = 1;
}
$fullEvent = $this->fetchEvent($user, $params);
if (!empty($fullEvent)) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->publishEvent($fullEvent[0], 'publish');
}
}
$fullEvent = $this->fetchEvent($user, $params);
if (!empty($fullEvent)) {
$pubSubTool->publishEvent($fullEvent[0], 'publish');
if ($pubToKafka) {
$params = array('eventid' => $id);
if (Configure::read('Plugin.Kafka_include_attachments')) {
$params['includeAttachments'] = 1;
}
$fullEvent = $this->fetchEvent($user, $params);
if (!empty($fullEvent)) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $fullEvent[0], 'publish');
}
}
}
}
@ -4836,7 +4879,8 @@ class Event extends AppModel
'name' => $object['name'],
'uuid' => $object['uuid'],
'id' => isset($object['id']) ? $object['id'] : 0,
'object_type' => $object['objectType']
'object_type' => $object['objectType'],
'relationship_type' => $reference['relationship_type']
);
}
}
@ -5702,14 +5746,20 @@ class Event extends AppModel
}
}
}
if ($saved == 1) {
$messageScopeSaved = Inflector::singularize($messageScope);
} else {
$messageScopeSaved = Inflector::pluralize($messageScope);
}
if ($failed > 0) {
if ($failed == 1) {
$message = $saved . ' ' . $messageScope . ' created' . $emailResult . '. ' . $failed . ' ' . $messageScope . ' could not be saved. Reason for the failure: ' . json_encode($lastError);
$messageScopeFailed = Inflector::singularize($messageScope);
$message = $saved . ' ' . $messageScopeSaved . ' created' . $emailResult . '. ' . $failed . ' ' . $messageScopeFailed . ' could not be saved. Reason for the failure: ' . json_encode($lastError);
} else {
$message = $saved . ' ' . $messageScope . ' created' . $emailResult . '. ' . $failed . ' ' . $messageScope . ' could not be saved. This may be due to attributes with similar values already existing.';
$message = $saved . ' ' . $messageScopeSaved . ' created' . $emailResult . '. ' . $failed . ' ' . $messageScope . ' could not be saved. This may be due to attributes with similar values already existing.';
}
} else {
$message = $saved . ' ' . $messageScope . ' created' . $emailResult . '.';
$message = $saved . ' ' . $messageScopeSaved . ' created' . $emailResult . '.';
}
if ($jobId) {
if ($i % 20 == 0) {
@ -5990,4 +6040,47 @@ class Event extends AppModel
}
return true;
}
public function getRequiredTaxonomies()
{
$this->Taxonomy = ClassRegistry::init('Taxonomy');
$required_taxonomies = $this->Taxonomy->find('list', array(
'recursive' => -1,
'conditions' => array('Taxonomy.required' => 1, 'Taxonomy.enabled' => 1),
'fields' => array('Taxonomy.namespace')
));
return $required_taxonomies;
}
public function checkIfPublishable($id)
{
$required_taxonomies = $this->getRequiredTaxonomies();
if (!empty($required_taxonomies)) {
$tags = $this->EventTag->find('all', array(
'conditions' => array('EventTag.event_id' => $id),
'recursive' => -1,
'contain' => array('Tag')
));
$missing = array();
foreach ($required_taxonomies as $required_taxonomy) {
$found = false;
foreach ($tags as $tag) {
$name = explode(':', $tag['Tag']['name']);
if (count($name) > 1) {
if ($name[0] == $required_taxonomy) {
$found = true;
break;
}
}
}
if (!$found) {
$missing[] = $required_taxonomy;
}
}
if (!empty($missing)) {
return $missing;
}
}
return true;
}
}

View File

@ -26,8 +26,10 @@ class EventTag extends AppModel
public function afterSave($created, $options = array())
{
parent::afterSave($created, $options);
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('EventTag.id' => $this->id),
@ -35,15 +37,24 @@ class EventTag extends AppModel
));
$tag['Tag']['event_id'] = $tag['EventTag']['event_id'];
$tag = array('Tag' => $tag['Tag']);
$pubSubTool->tag_save($tag, 'attached to event');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, 'attached to event');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, 'attached to event');
}
}
}
public function beforeDelete($cascade = true)
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
if (!empty($this->id)) {
$pubSubTool = $this->getPubSubTool();
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('EventTag.id' => $this->id),
@ -51,7 +62,14 @@ class EventTag extends AppModel
));
$tag['Tag']['event_id'] = $tag['EventTag']['event_id'];
$tag = array('Tag' => $tag['Tag']);
$pubSubTool->tag_save($tag, 'detached from event');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, 'detached from event');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, 'detached from event');
}
}
}
}

View File

@ -1,5 +1,6 @@
<?php
App::uses('AppModel', 'Model');
App::uses('RandomTool', 'Tools');
class Feed extends AppModel
{
@ -1393,4 +1394,112 @@ class Feed extends AppModel
}
return true;
}
public function getFeedCoverage($id, $source_scope = 'feed', $dataset = 'all')
{
$redis = $this->setupRedis();
if ($redis === false) {
return 'Could not reach Redis.';
}
$this->Server = ClassRegistry::init('Server');
$feed_conditions = array('Feed.caching_enabled' => 1);
$server_conditions = array('Server.caching_enabled' => 1);
if ($source_scope === 'feed') {
$feed_conditions['NOT'] = array('Feed.id' => $id);
} else {
$server_conditions['NOT'] = array('Server.id' => $id);
}
if ($dataset !== 'all') {
if (empty($dataset['Feed'])) {
$feed_conditions['OR'] = array('Feed.id' => -1);
} else {
$feed_conditions['OR'] = array('Feed.id' => $dataset['Feed']);
}
if (empty($dataset['Server'])) {
$server_conditions['OR'] = array('Server.id' => -1);
} else {
$server_conditions['OR'] = array('Server.id' => $dataset['Server']);
}
}
$other_feeds = $this->find('list', array(
'recursive' => -1,
'conditions' => $feed_conditions,
'fields' => array('Feed.id', 'Feed.id')
));
$other_servers = $this->Server->find('list', array(
'recursive' => -1,
'conditions' => $server_conditions,
'fields' => array('Server.id', 'Server.id')
));
$feed_element_count = $redis->scard('misp:feed_cache:' . $id);
$temp_store = (new RandomTool())->random_str(false, 12);
$params = array('misp:feed_temp:' . $temp_store);
foreach ($other_feeds as $other_feed) {
$params[] = 'misp:feed_cache:' . $other_feed;
}
foreach ($other_servers as $other_server) {
$params[] = 'misp:server_cache:' . $other_server;
}
if (count($params) != 1 && $feed_element_count > 0) {
call_user_func_array(array($redis, 'sunionstore'), $params);
call_user_func_array(array($redis, 'sinterstore'), array('misp:feed_temp:' . $temp_store . '_intersect', 'misp:feed_cache:' . $id, 'misp:feed_temp:' . $temp_store));
$cardinality_intersect = $redis->scard('misp:feed_temp:' . $temp_store . '_intersect');
$coverage = round(100 * $cardinality_intersect / $feed_element_count, 2);
$redis->del('misp:feed_temp:' . $temp_store);
$redis->del('misp:feed_temp:' . $temp_store . '_intersect');
} else {
$coverage = 0;
}
return $coverage;
}
public function getCachedElements($feedId)
{
$redis = $this->setupRedis();
$cardinality = $redis->sCard('misp:feed_cache:' . $feedId);
return $cardinality;
}
public function getAllCachingEnabledFeeds($feedId, $intersectingOnly = false) {
if ($intersectingOnly) {
$redis = $this->setupRedis();
}
$result['Feed'] = $this->find('all', array(
'conditions' => array(
'Feed.id !=' => $feedId,
'caching_enabled' => 1
),
'recursive' => -1,
'fields' => array('Feed.id', 'Feed.name', 'Feed.url')
));
$this->Server = ClassRegistry::init('Server');
$result['Server'] = $this->Server->find('all', array(
'conditions' => array(
'caching_enabled' => 1
),
'recursive' => -1,
'fields' => array('Server.id', 'Server.name', 'Server.url')
));
$scopes = array('Feed', 'Server');
foreach ($scopes as $scope) {
foreach ($result[$scope] as $k => $v) {
$result[$scope][$k] = $v[$scope];
}
}
if ($intersectingOnly) {
foreach ($scopes as $scope) {
if (!empty($result[$scope])) {
foreach ($result[$scope] as $k => $feed) {
$intersect = $redis->sInter('misp:feed_cache:' . $feedId, 'misp:' . lcfirst($scope) . '_cache:' . $feed['id']);
if (empty($intersect)) {
unset($result[$scope][$k]);
} else {
$result[$scope][$k]['matching_values'] = count($intersect);
}
}
}
}
}
return $result;
}
}

View File

@ -177,14 +177,14 @@ class Galaxy extends AppModel
$elements[] = array(
$galaxyClusterId,
$key,
$v
strval($v)
);
}
} else {
$elements[] = array(
$this->GalaxyCluster->id,
$key,
$value
strval($value)
);
}
}
@ -383,6 +383,20 @@ class Galaxy extends AppModel
return empty($galaxy) ? 0 : $galaxy['Galaxy']['id'];
}
public function getAllowedMatrixGalaxies()
{
$conditions = array(
'NOT' => array(
'kill_chain_order' => ''
)
);
$galaxies = $this->find('all', array(
'recursive' => -1,
'conditions' => $conditions,
));
return $galaxies;
}
public function getMatrix($galaxy_id)
{
$conditions = array('Galaxy.id' => $galaxy_id);

View File

@ -56,7 +56,7 @@ class Job extends AppModel
$process_id = CakeResque::enqueue(
'cache',
$shell . 'Shell',
array('cache' . $type, $user['id'], $id, $extra, $extra2),
array('cachebro' . $type, $user['id'], $id, $extra, $extra2),
true
);
} else {

View File

@ -256,11 +256,13 @@ class Log extends AppModel
public function logData($data)
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_user_notifications_enable')) {
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_audit_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->publish($data, 'audit', 'log');
}
$this->publishKafkaNotification('audit', $data, 'log');
if (Configure::read('Plugin.ElasticSearch_logging_enable')) {
// send off our logs to distributed /dev/null
$logIndex = Configure::read("Plugin.ElasticSearch_log_index");

View File

@ -92,19 +92,31 @@ class MispObject extends AppModel
public function afterSave($created, $options = array())
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_attribute_notifications_enable')) {
if (empty($this->data['Object']['skip_zmq'])) {
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') &&
Configure::read('Plugin.ZeroMQ_object_notifications_enable') &&
empty($this->data['Object']['skip_zmq']);
$kafkaTopic = Configure::read('Plugin.Kafka_object_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') &&
Configure::read('Plugin.Kafka_object_notifications_enable') &&
!empty($kafkaTopic) &&
empty($this->data['Object']['skip_kafka']);
if ($pubToZmq || $pubToKafka) {
$object = $this->find('first', array(
'conditions' => array('Object.id' => $this->id),
'recursive' => -1
));
$action = $created ? 'add' : 'edit';
if (!empty($this->data['Object']['deleted'])) {
$action = 'soft-delete';
}
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$object = $this->find('first', array(
'conditions' => array('Object.id' => $this->id),
'recursive' => -1
));
$action = $created ? 'add' : 'edit';
if (!empty($this->data['Object']['deleted'])) {
$action = 'soft-delete';
}
$pubSubTool->object_save($object, $action);
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $object, $action);
}
}
return true;
}
@ -112,13 +124,22 @@ class MispObject extends AppModel
public function beforeDelete($cascade = true)
{
if (!empty($this->data['Object']['id'])) {
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_object_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_object_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_object_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_object_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$object = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Object.id' => $this->data['Object']['id'])
));
$pubSubTool->object_save($object, 'delete');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->object_save($object, 'delete');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $object, 'delete');
}
}
}
}
@ -686,6 +707,7 @@ class MispObject extends AppModel
));
$object['Object']['timestamp'] = $date->getTimestamp();
$object['Object']['skip_zmq'] = 1;
$object['Object']['skip_kafka'] = 1;
$result = $this->save($object);
return $result;
}

View File

@ -55,8 +55,10 @@ class ObjectReference extends AppModel
public function afterSave($created, $options = array())
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_object_reference_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_object_reference_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_object_reference_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_object_reference_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$object_reference = $this->find('first', array(
'conditions' => array('ObjectReference.id' => $this->id),
'recursive' => -1
@ -65,7 +67,14 @@ class ObjectReference extends AppModel
if (!empty($this->data['ObjectReference']['deleted'])) {
$action = 'soft-delete';
}
$pubSubTool->object_reference_save($object_reference, $action);
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->object_reference_save($object_reference, $action);
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $object_reference, $action);
}
}
return true;
}

View File

@ -125,6 +125,8 @@ class Organisation extends AppModel
$pubSubTool = $this->getPubSubTool();
$pubSubTool->modified($this->data, 'organisation');
}
$action = $created ? 'add' : 'edit';
$this->publishKafkaNotification('organisation', $this->data, $action);
return true;
}

View File

@ -0,0 +1,40 @@
<?php
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')
),
);
public function cleanup($user_id)
{
$list = $this->find('list', array(
'conditions' => array(
'RestClientHistory.user_id' => $user_id
),
'page' => 1,
'limit' => 10,
'order' => array('RestClientHistory.timestamp DESC'),
'fields' => array('RestClientHistory.id', 'RestClientHistory.timestamp')
));
$this->deleteAll(array(
'RestClientHistory.user_id' => $user_id,
'RestClientHistory.bookmark' => 0,
'NOT' => array(
'RestClientHistory.id' => array_keys($list)
)
));
}
}

View File

@ -140,6 +140,12 @@ class Role extends AppModel
'text' => 'ZMQ publisher',
'readonlyenabled' => false,
'title' => 'Allow users to publish data to the ZMQ pubsub channel via the publish event to ZMQ button.'
),
'perm_publish_kafka' => array(
'id' => 'RolePermPublishKafka',
'text' => 'Kafka publisher',
'readonlyenabled' => false,
'title' => 'Allow users to publish data to Kafka via the publish event to Kafka button.'
)
);

View File

@ -250,6 +250,15 @@ class Server extends AppModel
'type' => 'boolean',
'afterHook' => 'disableCacheAfterHook',
),
'disable_threat_level' => array(
'level' => 1,
'description' => __('Disable displaying / modifications to the threat level altogether on the instance (deprecated field).'),
'value' => false,
'null' => true,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'header' => array(
'level' => 3,
'description' => __('This setting is deprecated and can be safely removed.'),
@ -1288,6 +1297,214 @@ class Server extends AppModel
'test' => 'testForEmpty',
'type' => 'string',
),
'Kafka_enable' => array(
'level' => 2,
'description' => __('Enables or disables the Kafka pub feature of MISP. Make sure that you install the requirements for the plugin to work. Refer to the installation instructions for more information.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean',
),
'Kafka_brokers' => array(
'level' => 2,
'description' => __('A comma separated list of Kafka bootstrap brokers'),
'value' => 'kafka:9092',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'Kafka_rdkafka_config' => array(
'level' => 2,
'description' => __('A path to an ini file with configuration options to be passed to rdkafka. Section headers in the ini file will be ignored.'),
'value' => '/etc/rdkafka.ini',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string',
),
'Kafka_include_attachments' => array(
'level' => 2,
'description' => __('Enable this setting to include the base64 encoded payloads of malware-samples/attachments in the output.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_event_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any event creations/edits/deletions.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_event_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing event creations/edits/deletions.'),
'value' => 'misp_event',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_event_publish_notifications_enable' => array(
'level' => 2,
'description' => __('If enabled it will publish to Kafka the event at the time that the event gets published in MISP. Event actions (creation or edit) will not be published to Kafka.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_event_publish_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing event information on publish.'),
'value' => 'misp_event_publish',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_object_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any object creations/edits/deletions.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_object_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing object creations/edits/deletions.'),
'value' => 'misp_object',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_object_reference_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any object reference creations/deletions.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_object_reference_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing object reference creations/deletions.'),
'value' => 'misp_object_reference',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_attribute_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any attribute creations/edits/soft deletions.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_attribute_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing attribute creations/edits/soft deletions.'),
'value' => 'misp_attribute',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_shadow_attribute_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any proposal creations/edits/deletions.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_shadow_attribute_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing proposal creations/edits/deletions.'),
'value' => 'misp_shadow_attribute',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_tag_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of any tag creations/edits/deletions as well as tags being attached to / detached from various MISP elements.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_tag_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing tag creations/edits/deletions as well as tags being attached to / detached from various MISP elements.'),
'value' => 'misp_tag',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_sighting_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of new sightings.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_sighting_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing sightings.'),
'value' => 'misp_sighting',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_user_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of new/modified users.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_user_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing new/modified users.'),
'value' => 'misp_user',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_organisation_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of new/modified organisations.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_organisation_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing new/modified organisations.'),
'value' => 'misp_organisation',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'Kafka_audit_notifications_enable' => array(
'level' => 2,
'description' => __('Enables or disables the publishing of log entries. Keep in mind, this can get pretty verbose depending on your logging settings.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
'type' => 'boolean'
),
'Kafka_audit_notifications_topic' => array(
'level' => 2,
'description' => __('Topic for publishing log entries.'),
'value' => 'misp_audit',
'errorMessage' => '',
'test' => 'testForEmpty',
'type' => 'string'
),
'ZeroMQ_enable' => array(
'level' => 2,
'description' => __('Enables or disables the pub/sub feature of MISP. Make sure that you install the requirements for the plugin to work. Refer to the installation instructions for more information.'),

View File

@ -277,6 +277,10 @@ class ShadowAttribute extends AppModel
} else {
$this->__afterSaveCorrelation($this->data['ShadowAttribute']);
}
if (empty($this->data['ShadowAttribute']['deleted'])) {
$action = $created ? 'add' : 'edit';
$this->publishKafkaNotification('shadow_attribute', $this->data, $action);
}
return $result;
}
@ -555,6 +559,7 @@ class ShadowAttribute extends AppModel
}
$fieldList = array('proposal_email_lock', 'id', 'info');
$event['Event']['skip_zmq'] = 1;
$event['Event']['skip_kafka'] = 1;
$this->Event->save($event, array('fieldList' => $fieldList));
}

View File

@ -60,8 +60,10 @@ class Sighting extends AppModel
public function afterSave($created, $options = array())
{
parent::afterSave($created, $options = array());
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_sighting_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_sighting_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_sighting_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_sighting_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$user = array(
'org_id' => -1,
'Role' => array(
@ -69,7 +71,14 @@ class Sighting extends AppModel
)
);
$sighting = $this->getSighting($this->id, $user);
$pubSubTool->sighting_save($sighting, 'add');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->sighting_save($sighting, 'add');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $sighting, 'add');
}
}
return true;
}
@ -77,8 +86,10 @@ class Sighting extends AppModel
public function beforeDelete($cascade = true)
{
parent::beforeDelete();
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_sighting_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_sighting_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_sighting_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_sighting_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$user = array(
'org_id' => -1,
'Role' => array(
@ -86,7 +97,14 @@ class Sighting extends AppModel
)
);
$sighting = $this->getSighting($this->id, $user);
$pubSubTool->sighting_save($sighting, 'delete');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->sighting_save($sighting, 'delete');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $sighting, 'delete');
}
}
}

View File

@ -90,27 +90,45 @@ class Tag extends AppModel
public function afterSave($created, $options = array())
{
parent::afterSave($created, $options);
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Tag.id' => $this->id)
));
$action = $created ? 'add' : 'edit';
$pubSubTool->tag_save($tag, $action);
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, $action);
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, $action);
}
}
}
public function beforeDelete($cascade = true)
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable')) {
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_tag_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_tag_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_tag_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
if (!empty($this->id)) {
$pubSubTool = $this->getPubSubTool();
$tag = $this->find('first', array(
'recursive' => -1,
'conditions' => array('Tag.id' => $this->id)
));
$pubSubTool->tag_save($tag, 'delete');
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->tag_save($tag, 'delete');
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $tag, 'delete');
}
}
}
}

View File

@ -362,6 +362,72 @@ class Taxonomy extends AppModel
return true;
}
public function hideTags($id, $tagList = false)
{
if ($tagList && !is_array($tagList)) {
$tagList = array($tagList);
}
$this->Tag = ClassRegistry::init('Tag');
App::uses('ColourPaletteTool', 'Tools');
$paletteTool = new ColourPaletteTool();
$taxonomy = $this->__getTaxonomy($id, array('full' => true));
$tags = $this->Tag->getTagsForNamespace($taxonomy['Taxonomy']['namespace']);
$colours = $paletteTool->generatePaletteFromString($taxonomy['Taxonomy']['namespace'], count($taxonomy['entries']));
foreach ($taxonomy['entries'] as $k => $entry) {
$colour = $colours[$k];
if (isset($entry['colour']) && !empty($entry['colour'])) {
$colour = $entry['colour'];
}
if ($tagList) {
foreach ($tagList as $tagName) {
if ($tagName === $entry['tag']) {
if (isset($tags[strtoupper($entry['tag'])])) {
$this->Tag->quickEdit($tags[strtoupper($entry['tag'])], $tagName, $colour, 1);
}
}
}
} else {
if (isset($tags[strtoupper($entry['tag'])])) {
$this->Tag->quickEdit($tags[strtoupper($entry['tag'])], $entry['tag'], $colour, 1);
}
}
}
return true;
}
public function unhideTags($id, $tagList = false)
{
if ($tagList && !is_array($tagList)) {
$tagList = array($tagList);
}
$this->Tag = ClassRegistry::init('Tag');
App::uses('ColourPaletteTool', 'Tools');
$paletteTool = new ColourPaletteTool();
$taxonomy = $this->__getTaxonomy($id, array('full' => true));
$tags = $this->Tag->getTagsForNamespace($taxonomy['Taxonomy']['namespace']);
$colours = $paletteTool->generatePaletteFromString($taxonomy['Taxonomy']['namespace'], count($taxonomy['entries']));
foreach ($taxonomy['entries'] as $k => $entry) {
$colour = $colours[$k];
if (isset($entry['colour']) && !empty($entry['colour'])) {
$colour = $entry['colour'];
}
if ($tagList) {
foreach ($tagList as $tagName) {
if ($tagName === $entry['tag']) {
if (isset($tags[strtoupper($entry['tag'])])) {
$this->Tag->quickEdit($tags[strtoupper($entry['tag'])], $tagName, $colour, 0);
}
}
}
} else {
if (isset($tags[strtoupper($entry['tag'])])) {
$this->Tag->quickEdit($tags[strtoupper($entry['tag'])], $entry['tag'], $colour, 0);
}
}
}
return true;
}
public function listTaxonomies($options = array('full' => false, 'enabled' => false))
{
$recursive = -1;

View File

@ -271,8 +271,10 @@ class User extends AppModel
public function afterSave($created, $options = array())
{
if (Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_user_notifications_enable')) {
$pubSubTool = $this->getPubSubTool();
$pubToZmq = Configure::read('Plugin.ZeroMQ_enable') && Configure::read('Plugin.ZeroMQ_user_notifications_enable');
$kafkaTopic = Configure::read('Plugin.Kafka_user_notifications_topic');
$pubToKafka = Configure::read('Plugin.Kafka_enable') && Configure::read('Plugin.Kafka_user_notifications_enable') && !empty($kafkaTopic);
if ($pubToZmq || $pubToKafka) {
if (!empty($this->data)) {
$user = $this->data;
if (!isset($user['User'])) {
@ -298,7 +300,14 @@ class User extends AppModel
unset($user['User']['password']);
unset($user['User']['confirm_password']);
}
$pubSubTool->modified($user, 'user', $action);
if ($pubToZmq) {
$pubSubTool = $this->getPubSubTool();
$pubSubTool->modified($user, 'user', $action);
}
if ($pubToKafka) {
$kafkaPubTool = $this->getKafkaPubTool();
$kafkaPubTool->publishJson($kafkaTopic, $user, $action);
}
}
}
return true;

12
app/View/Attributes/index.ctp Normal file → Executable file
View File

@ -46,7 +46,7 @@
$headers = array(
$this->Paginator->sort('date'),
$this->Paginator->sort('event_id'),
$this->Paginator->sort('Event.orgc_id', 'Org'),
$this->Paginator->sort('Event.orgc_id', __('Org')),
$this->Paginator->sort('category'),
$this->Paginator->sort('type'),
$this->Paginator->sort('value'),
@ -56,18 +56,14 @@
__('Correlate'),
__('Related Events'),
__('Feed hits'),
sprintf('<span title="%s">%s</th>', $attrDescriptions['signature']['desc'], $this->Paginator->sort('IDS')),
$this->Paginator->sort('distribution'),
sprintf('<span title="%s">%s', $attrDescriptions['signature']['desc'], $this->Paginator->sort('IDS')),
sprintf('<span title="%s">%s', $attrDescriptions['distribution']['desc'], $this->Paginator->sort('distribution')),
__('Sightings'),
__('Activity'),
__('Actions')
);
foreach ($headers as $k => &$header) {
if ($k == (count($headers)-1)) {
$header = sprintf('<th title="%s">%s</th>', $attrDescriptions['signature']['desc'], $header);
} else {
$header = sprintf('<th>%s</th>', $header);
}
$header = sprintf('<th>%s</th>', $header);
}
$rows = array(
sprintf('<tr>%s</tr>', implode('', $headers))

View File

@ -35,7 +35,7 @@
?>
</fieldset>
<?php
echo $this->Form->button('Search', array('class' => 'btn btn-primary'));
echo $this->Form->button(__('Search'), array('class' => 'btn btn-primary'));
echo $this->Form->end();
?>
</div>

View File

@ -24,7 +24,7 @@
endif;
if ($isSiteAdmin):
?>
<th class="filter"><?php echo $this->Paginator->sort('owner org');?></th>
<th class="filter"><?php echo $this->Paginator->sort('owner org', __('Owner org'));?></th>
<?php
endif;
endif;
@ -36,7 +36,7 @@
<?php if (Configure::read('MISP.tagging')): ?>
<th class="filter"><?php echo __('Tags');?></th>
<?php endif; ?>
<th title="<?php echo __('Attribute Count');?>"><?php echo $this->Paginator->sort('attribute_count', '#Attr.');?></th>
<th title="<?php echo __('Attribute Count');?>"><?php echo $this->Paginator->sort('attribute_count', __('#Attr.'));?></th>
<?php if (Configure::read('MISP.showCorrelationsOnIndex')):?>
<th title="<?php echo __('Correlation Count');?>"><?php echo __('#Corr.');?></th>
<?php endif; ?>
@ -50,14 +50,14 @@
<th title="<?php echo __('Post Count');?>"><?php echo __('#Posts');?></th>
<?php endif; ?>
<?php if ($isSiteAdmin): ?>
<th><?php echo $this->Paginator->sort('user_id', 'Email');?></th>
<th><?php echo $this->Paginator->sort('user_id', __('Email'));?></th>
<?php endif; ?>
<th class="filter"><?php echo $this->Paginator->sort('date', null, array('direction' => 'desc'));?></th>
<th class="filter"><?php echo $this->Paginator->sort('info');?></th>
<th title="<?php echo $eventDescriptions['distribution']['desc'];?>">
<?php echo $this->Paginator->sort('distribution');?>
</th>
<th class="actions">Actions</th>
<th class="actions"><?php echo __('Actions');?></th>
</tr>
<?php foreach ($events as $event): ?>
@ -79,11 +79,11 @@
<?php
if ($event['Event']['published'] == 1) {
?>
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" title = "<?php echo __('View');?>"><i class="black fa fa-check"></i></a>
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"><i class="black fa fa-check"></i></a>
<?php
} else {
?>
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" title = "<?php echo __('View');?>"><i class="black fa fa-times"></i></a>
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>" title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"><i class="black fa fa-times"></i></a>
<?php
}?>&nbsp;
</td>
@ -135,7 +135,7 @@
<span class="blue">
&nbsp;
<a href="<?php echo $baseurl; ?>/events/index/searchtag:<?php echo h($cluster['tag_id']); ?>"><?php echo h($cluster['value']); ?></a>
<a href="<?php echo $baseurl; ?>/galaxy_clusters/view/<?php echo h($cluster['id']); ?>"><i class="black fa fa-search"></i></a>
<a aria-label="<?php echo __('View cluster');?>" href="<?php echo $baseurl; ?>/galaxy_clusters/view/<?php echo h($cluster['id']); ?>"><i class="black fa fa-search"></i></a>
</span>
<?php
endforeach;
@ -214,22 +214,32 @@
echo h($shortDist[$event['Event']['distribution']]);
endif;
?>
<?php
echo sprintf(
'<it type="button" title="%s" class="%s" aria-hidden="true" style="font-size: x-small;" data-event-distribution="%s" data-event-distribution-name="%s" data-scope-id="%s"></it>',
'Toggle advanced sharing network viewer',
'fa fa-share-alt useCursorPointer distributionNetworkToggle',
h($event['Event']['distribution']),
$event['Event']['distribution'] == 4 ? h($event['SharingGroup']['name']) : h($shortDist[$event['Event']['distribution']]),
h($event['Event']['id'])
)
?>
</td>
<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', $event['Event']['id']), array('class' => 'black fa fa-upload', 'title' => __('Publish Event'), __('Are you sure this event is complete and everyone should be informed?')));
echo $this->Form->postLink('', array('action' => 'alert', $event['Event']['id']), 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?'));
else if (0 == $event['Event']['published']) echo __('Not published');
if ($isSiteAdmin || ($isAclModify && $event['Event']['user_id'] == $me['id']) || ($isAclModifyOrg && $event['Event']['orgc_id'] == $me['org_id'])):
?>
<a href='<?php echo $baseurl."/events/edit/".$event['Event']['id'];?>' title = "<?php echo __('Edit');?>"><i class="black fa fa-edit"></i></a>
<a href='<?php echo $baseurl."/events/edit/".$event['Event']['id'];?>' title = "<?php echo __('Edit');?>" aria-label = "<?php echo __('Edit');?>"><i class="black fa fa-edit"></i></a>
<?php
echo $this->Form->postLink('', array('action' => 'delete', $event['Event']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete')), __('Are you sure you want to delete # %s?', $event['Event']['id']));
echo $this->Form->postLink('', array('action' => 'delete', $event['Event']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete'), 'aria-label' => __('Delete')), __('Are you sure you want to delete # %s?', $event['Event']['id']));
endif;
?>
<a href='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>' title = "<?php echo __('View');?>"><i class="fa black fa-eye"></i></a>
<a href='<?php echo $baseurl."/events/view/".$event['Event']['id'];?>' title = "<?php echo __('View');?>" aria-label = "<?php echo __('View');?>"><i class="fa black fa-eye"></i></a>
</td>
</tr>
<?php endforeach; ?>
@ -239,5 +249,11 @@
$('.select').on('change', function() {
listCheckboxesChecked();
});
$('.distributionNetworkToggle').each(function() {
$(this).distributionNetwork({
distributionData: <?php echo json_encode($distributionData); ?>,
});
});
});
</script>

View File

@ -0,0 +1,87 @@
<?php
$progress_bar = sprintf(
'<div class="span11 progress" style="margin-left:0px;"><div id="feed_coverage_bar" class="bar" style="width: %s;">%s</div></div><div class="span1">&nbsp;</div><br /><br />',
(empty($feed['Feed']['coverage_by_selected_feeds']) ? h($feed['Feed']['coverage_by_other_feeds']) : h($feed['Feed']['coverage_by_selected_feeds'])),
(empty($feed['Feed']['coverage_by_selected_feeds']) ? h($feed['Feed']['coverage_by_other_feeds']) : h($feed['Feed']['coverage_by_selected_feeds']))
);
echo sprintf(
'<h3>%s</h3><p class="bold">%s</p>%s',
__('Feed coverage tool'),
__('Coverage by currently selected sources: '),
$progress_bar
);
$options = array(
'Server' => array(
'left' => array(), 'right' => array()
),
'Feed' => array(
'left' => array(), 'right' => array()
)
);
//debug($other_feeds);
foreach (array_keys($options) as $scope) {
array_multisort(array_column($other_feeds[$scope], 'matching_values'), SORT_DESC, $other_feeds[$scope]);
}
foreach ($options as $scope => $temp) {
if (!empty($other_feeds[$scope])) {
foreach ($other_feeds[$scope] as $other_feed) {
if (!empty($other_feed['exclude'])) {
$options[$scope]['right'][$other_feed['name']] = $other_feed;
} else {
$options[$scope]['left'][$other_feed['name']] = $other_feed;
}
}
}
}
foreach ($options as $scope => $data) {
$temp = array('left' => array(), 'right' => array());
foreach ($data as $side => $data_points) {
if (!empty($data[$side])) {
foreach ($data_points as $data_point) {
$temp[$side][] = sprintf(
'<option value=%s>%s</option>',
h($data_point['id']),
sprintf(
'[%s%%] %s',
round(100 * $data_point['matching_values'] / $feed['Feed']['cached_elements']),
h($data_point['name'])
)
);
}
}
}
echo sprintf(
'<h4>%s</h4><div class="row-fluid"><div class="span5">%s</div><div class="span1" style="text-align:center;margin-top:50px;">%s</div><div class="span5">%s</div></div>',
h($scope),
sprintf(
'<b class="bold">%s</b><select id="%s" class="picker-%s" style="width:100%%;" size="5" multiple="multiple" data-pickername="%s">%s</select>',
__('Include'),
h($scope) . 'Left',
'left',
h($scope),
implode('', $temp['left'])
),
sprintf(
'<button class="btn btn-inverse btn-small" onclick="generic_picker_move(%s, %s);" title="Include selected">&lt;&lt;</button>
<button class="btn btn-inverse btn-small" onclick="generic_picker_move(%s, %s);" title="Include selected">&gt;&gt;</button>',
'\'' . h($scope) . '\'',
"'left'",
'\'' . h($scope) . '\'',
"'right'"
),
sprintf(
'<b class="bold">%s</b><select id="%s" class="picker-%s" style="width:100%%;" size="5" multiple="multiple" data-pickername="%s">%s</select>',
__('Exclude'),
h($scope) . 'Right',
'right',
h($scope),
implode('', $temp['right'])
)
);
}
echo sprintf(
'<button class="btn btn-primary" onClick="submit_feed_overlap_tool(%s);">%s</button>',
h($feed['Feed']['id']),
__('Check coverage')
);

2
app/View/Elements/Feeds/View/row_attribute.ctp Normal file → Executable file
View File

@ -84,7 +84,7 @@ if ($object['value'] == 'MERGE') debug($object);
</td>
<td class="short">
<div id = "Attribute_<?php echo $object['uuid']; ?>_to_ids_solid" class="inline-field-solid");">
<?php echo $object['to_ids'] ? 'Yes' : 'No'; ?>
<?php echo $object['to_ids'] ? __('Yes') : __('No'); ?>
</div>
</td>
</td>

View File

@ -38,7 +38,7 @@
<div id="attributeList" class="attributeListContainer">
<table class="table table-striped table-condensed">
<tr>
<th><?php echo $this->Paginator->sort('timestamp', 'Date');?></th>
<th><?php echo $this->Paginator->sort('timestamp', __('Date'));?></th>
<th><?php echo $this->Paginator->sort('category');?></th>
<th><?php echo $this->Paginator->sort('type');?></th>
<th><?php echo $this->Paginator->sort('value');?></th>

View File

@ -40,13 +40,14 @@
<td class="short action-links">
<?php
if ($isSiteAdmin || $me['org_id'] == $item['TagCollection']['org_id']) {
echo $this->Html->link('', array('action' => 'edit', $item['TagCollection']['id']), array('class' => 'fa fa-edit', 'title' => 'Edit'));
echo $this->Form->postLink('', array('action' => 'delete', $item['TagCollection']['id']), array('class' => 'fa fa-trash', 'title' => 'Delete'), __('Are you sure you want to delete "%s"?', $item['TagCollection']['name']));
echo $this->Html->link('', array('action' => 'edit', $item['TagCollection']['id']), array('class' => 'fa fa-edit', 'title' => __('Edit')));
echo $this->Form->postLink('', array('action' => 'delete', $item['TagCollection']['id']), array('class' => 'fa fa-trash', 'title' => __('Delete')), __('Are you sure you want to delete "%s"?', $item['TagCollection']['name']));
}
echo sprintf(
'<a href="%s/tag_collections/view/%s.json" class="fa fa-cloud-download black" title="Download configuration" download="tag_collection_%s.json"></a>',
'<a href="%s/tag_collections/view/%s.json" class="fa fa-cloud-download black" title="%s" download="tag_collection_%s.json"></a>',
$baseurl,
h($item['TagCollection']['id']),
__('Download configuration'),
h($item['TagCollection']['id'])
);

View File

@ -1,3 +1,24 @@
<?php
if (!empty($required_taxonomies)) {
foreach ($required_taxonomies as $k => $v) {
foreach ($tags as $tag) {
$temp_tag = explode(':', $tag['Tag']['name']);
if (count($temp_tag) > 1) {
if ($temp_tag[0] == $v) {
unset($required_taxonomies[$k]);
break;
}
}
}
}
if (!empty($required_taxonomies)) {
echo sprintf(
'Missing taxonomies: <span class="red bold">%s</span><br />',
implode(', ', $required_taxonomies)
);
}
}
?>
<span style="display:inline-block;">
<?php
$full = $isAclTagger && $tagAccess;

View File

@ -137,15 +137,15 @@
?>
<th class="context hidden"><?php echo $this->Paginator->sort('id');?></th>
<th class="context hidden">UUID</th>
<th><?php echo $this->Paginator->sort('timestamp', 'Date', array('direction' => 'desc'));?></th>
<th><?php echo $this->Paginator->sort('timestamp', __('Date'), array('direction' => 'desc'));?></th>
<?php
if ($extended):
?>
<th class="event_id"><?php echo $this->Paginator->sort('event_id', 'Event');?></th>
<th class="event_id"><?php echo $this->Paginator->sort('event_id', __('Event'));?></th>
<?php
endif;
?>
<th><?php echo $this->Paginator->sort('Org.name', 'Org'); ?>
<th><?php echo $this->Paginator->sort('Org.name', __('Org')); ?>
<th><?php echo $this->Paginator->sort('category');?></th>
<th><?php echo $this->Paginator->sort('type');?></th>
<th><?php echo $this->Paginator->sort('value');?></th>

2
app/View/Elements/galaxyQuickView.ctp Normal file → Executable file
View File

@ -93,7 +93,7 @@
<?php
if ($isSiteAdmin || ($mayModify && $isAclTagger)):
?>
<span class="useCursorPointer btn btn-inverse addGalaxy" data-target-type="<?php echo h($target_type);?>" data-target-id="<?php echo h($target_id); ?>" role="button" tabindex="0" aria-label="Add new cluster" style="padding: 1px 5px !important;font-size: 12px !important;">Add</span>
<span class="useCursorPointer btn btn-inverse addGalaxy" data-target-type="<?php echo h($target_type);?>" data-target-id="<?php echo h($target_id); ?>" role="button" tabindex="0" aria-label="Add new cluster" style="padding: 1px 5px !important;font-size: 12px !important;"><?php echo __('Add'); ?></span>
<?php
endif;
?>

View File

@ -17,6 +17,14 @@
'text' => __('Populate From Template')
));
}
if ($menuItem === 'enrichmentResults') {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'enrichmentResults',
'url' => '#',
'text' => __('Enrichment Module Result')
));
echo $this->element('/genericElements/SideMenu/side_menu_divider');
}
if ($menuItem === 'freetextResults') {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'freetextResults',
@ -173,6 +181,16 @@
'message' => __('Are you sure you wish to republish the current event to the ZMQ channel?')
));
}
if (Configure::read('Plugin.Kafka_enable') &&
Configure::read('Plugin.Kafka_event_notifications_enable') &&
Configure::read('Plugin.Kafka_event_notifications_topic') &&
$isAclKafka) {
echo $this->element('/genericElements/SideMenu/side_menu_post_link', array(
'url' => '/events/pushEventToKafka/' . h($event['Event']['id']),
'text' => __('Publish event to Kafka'),
'message' => __('Are you sure you wish to republish the current event to the Kafka topic?')
));
}
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'contact',
'url' => '/events/contact/' . $event['Event']['id'],
@ -638,11 +656,6 @@
));
}
if ($menuItem === 'editOrg' || $menuItem === 'viewOrg') {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'editOrg',
'url' => '/organisations/edit/' . h($id),
'text' => __('Edit Organisation')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'viewOrg',
'url' => '/organisations/view/' . h($id),
@ -884,11 +897,17 @@
'download' => 'feed_index.json'
));
if ($isSiteAdmin) {
if ($menuItem === 'edit') {
if ($menuItem === 'edit' || $menuItem === 'view') {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'edit',
'url' => '/feeds/edit/' . h($feed['Feed']['id']),
'text' => __('Edit Feed')
));
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'view',
'url' => '/feeds/view/' . h($feed['Feed']['id']),
'text' => __('View Feed')
));
} else if ($menuItem === 'previewIndex') {
echo $this->element('/genericElements/SideMenu/side_menu_link', array(
'element_id' => 'previewIndex',

View File

@ -105,7 +105,6 @@ function redrawChosenWithTemplate($select, $chosenContainer, eventType) {
if (optionLength > 1000) {
$chosenContainer.parent().find('.generic-picker-wrapper-warning-text').show(0)
} else {
console.log(eventType);
$chosenContainer.find('.generic-picker-wrapper-warning-text').hide(0)
var $matches;
if (eventType == 'chosen:picked' || eventType == 'change') {
@ -284,5 +283,4 @@ function submitFunction(clicked, callback) {
options_templates['<?php echo $select_id; ?>'] = <?php echo json_encode($option_templates); ?>;
options_additionalData['<?php echo $select_id; ?>'] = <?php echo json_encode($options_additionalData); ?>;
</script>
</div>

2
app/View/Elements/generic_table.ctp Normal file → Executable file
View File

@ -5,7 +5,7 @@
'before' => '$(".progress").show()',
'complete' => '$(".progress").hide()',
));
$title = sprintf('<h2>%s</h2>', Inflector::humanize($controller));
$title = sprintf('<h2>%s</h2>', $alias);
if (!empty($description)) {
$description = sprintf('<p>%s</p>', Inflector::humanize($description));
} else {

2
app/View/Elements/global_menu.ctp Normal file → Executable file
View File

@ -4,7 +4,7 @@
array(
'type' => 'root',
'url' => $baseurl . '/',
'html' => (Configure::read('MISP.home_logo') ? $logo = '<img src="' . $baseurl . '/img/custom/' . Configure::read('MISP.home_logo') . '" style="height:24px;">' : 'Home')
'html' => (Configure::read('MISP.home_logo') ? $logo = '<img src="' . $baseurl . '/img/custom/' . Configure::read('MISP.home_logo') . '" style="height:24px;">' : __('Home'))
),
array(
'type' => 'root',

View File

@ -65,7 +65,7 @@
'title' => __('Download report'),
'html' => '<i class="fa fa-download"></i>'
);
if ($active_tab && $active_tab !== 'diagnostics' && $active_tab !== 'files') {
if ($active_tab && !in_array($active_tab, array('diagnostics', 'files', 'workers'))) {
$data['children'][] = array(
'type' => 'live_search',
'placeholder' => 'Filter the table(s) below'

2
app/View/Elements/serverRuleElements/pull.ctp Normal file → Executable file
View File

@ -35,7 +35,7 @@
</tr>
<tr>
<td style="width:120px;">
<p style="color:green;font-weight:bold;">Allowed Orgs (OR)</p>
<p style="color:green;font-weight:bold;"><?php echo __('Allowed Orgs (OR)');?></p>
<select id="orgspullLeftValues" size="5" multiple style="width:185px;">
</select>
</td>

View File

@ -8,7 +8,8 @@
<div class="spinner"></div>
<div class="loadingText"><?php echo __('Loading');?></div>
</div>
<div id="eventdistri_graph" data-event-id="<?php echo h($event['Event']['id']); ?>" data-event-distribution="<?php echo h($event['Event']['distribution']); ?>" data-user-manipulation="<?php echo $mayModify || $isSiteAdmin ? 'true' : 'false'; ?>" data-extended="<?php echo $extended; ?>">
<div id="eventdistri_graph" data-event-id="<?php echo h($event['Event']['id']); ?>" data-event-distribution="<?php echo h($event['Event']['distribution']); ?>" data-event-distribution-text="<?php echo $event['Event']['distribution'] == 4 ? h($event['SharingGroup']['name']) : h($distributionLevels[$event['Event']['distribution']]); ?>" data-user-manipulation="<?php echo $mayModify || $isSiteAdmin ? 'true' : 'false'; ?>" data-extended="<?php echo $extended; ?>">
<canvas id="distribution_graph_canvas" height="290px"width="400px"></canvas>
</div>
<div class="popupDistriSeparator"></div>

2
app/View/Elements/view_event_graph.ctp Normal file → Executable file
View File

@ -15,7 +15,7 @@
<label id="network-import" class="btn center-in-network-header network-control-btn"><span class="useCursorPointer fa fa-exchange" style="margin-right: 3px;"></span><?php echo __('Export')?></label>
<label id="network-history" class="btn center-in-network-header network-control-btn"><span class="useCursorPointer fa fa-history" style="margin-right: 3px;"></span><?php echo __('History')?></label>
<input type="text" id="network-typeahead" class="center-in-network-header network-typeahead flushright" data-provide="typeahead" size="20" placeholder="Search for an item">
<input type="text" id="network-typeahead" class="center-in-network-header network-typeahead flushright" data-provide="typeahead" size="20" placeholder="<?php echo __('Search for an item');?>">
</div>
<span class="shortcut-help btn btn-xs btn-info">?</span>

View File

@ -33,17 +33,19 @@
?>
</div>
<?php
if (isset($this->request->data['Event']['threat_level_id'])) {
$selected = $this->request->data['Event']['threat_level_id'];
} else {
$selected = Configure::read('MISP.default_event_threat_level') ? Configure::read('MISP.default_event_threat_level') : '4';
}
echo '<div class="input clear"></div>';
if (empty(Configure::read('MISP.disable_threat_level'))) {
if (isset($this->request->data['Event']['threat_level_id'])) {
$selected = $this->request->data['Event']['threat_level_id'];
} else {
$selected = Configure::read('MISP.default_event_threat_level') ? Configure::read('MISP.default_event_threat_level') : '4';
}
echo $this->Form->input('threat_level_id', array(
'div' => 'input clear',
'label' => __('Threat Level ') . $this->element('formInfo', array('type' => 'threat_level')),
'selected' => $selected,
));
echo $this->Form->input('threat_level_id', array(
'label' => __('Threat Level ') . $this->element('formInfo', array('type' => 'threat_level')),
'selected' => $selected,
));
}
echo $this->Form->input('analysis', array(
'label' => __('Analysis ') . $this->element('formInfo', array('type' => 'analysis')),
'options' => array($analysisLevels),

View File

@ -0,0 +1,8 @@
<?php
echo $this->Form->create($scope, array('url' => array('controller' => Inflector::tableize($scope), 'action' => 'addTag', $object_id)));
if ($scope === 'Attribute') {
echo $this->Form->input('attribute_ids', array());
}
echo $this->Form->input('tag', array('value' => 0));
echo $this->Form->end();
?>

View File

@ -30,10 +30,12 @@ $mayPublish = ($isAclPublish && $event['Event']['orgc_id'] == $me['org_id']);
?>
</div>
<?php
echo $this->Form->input('threat_level_id', array(
'div' => 'input clear',
echo '<div class="input clear"></div>';
if (empty(Configure::read('MISP.disable_threat_level'))) {
echo $this->Form->input('threat_level_id', array(
'label' => __('Threat Level ') . $this->element('formInfo', array('type' => 'threat_level'))
));
));
}
echo $this->Form->input('analysis', array(
'label' => __('Analysis ') . $this->element('formInfo', array('type' => 'analysis')),
'options' => array($analysisLevels)

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