Merge remote-tracking branch 'upstream/2.4' into bug/galaxy_cluster

pull/6932/head
Tom King 2021-02-17 09:56:08 +00:00
commit 8077eeaa3c
138 changed files with 1924 additions and 15553 deletions

View File

@ -20,7 +20,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
os: [ubuntu-20.04]
php: ['7.2', '7.3', '7.4']
# Steps represent a sequence of tasks that will be executed as part of the job
@ -66,9 +66,14 @@ jobs:
run: |
git submodule update --init --recursive
sudo apt-get -y update
sudo apt-get -y install curl python3 python3-venv virtualenv python3-pip python3-nose python3-redis python3-lxml apache2 libapache2-mod-php$php_version php$php_version-xml php$php_version-mbstring php$php_version-mysql libfuzzy-dev libemail-address-perl libemail-outlook-message-perl
sudo pip3 install --upgrade pip setuptools requests pyzmq poetry
if [[ $php_version == "7.4" ]]; then
# Repo is missing for unknown reason
LC_ALL=C.UTF-8 sudo apt-add-repository ppa:ondrej/php -y
fi
sudo apt-get -y install curl python3 python3-zmq python3-requests python3-pip python3-nose python3-redis python3-lxml apache2 libapache2-mod-php$php_version libfuzzy-dev
sudo pip3 install virtualenv # virtualenv must be instaled from pip and not from ubuntu pacckages
sudo pip3 install --upgrade -r requirements.txt
curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -
sudo chown $USER:www-data $HOME/.composer
pushd app
sudo -H -u $USER php composer.phar install --no-progress
@ -185,7 +190,7 @@ jobs:
sudo chmod -R 777 ./tests
# Start workers
# Dirty install python stuff
virtualenv -p python3 ./venv
python3 -m virtualenv -p python3 ./venv
sudo -E su $USER -c 'app/Console/cake Admin setSetting "MISP.python_bin" "$GITHUB_WORKSPACE/venv/bin/python"'
. ./venv/bin/activate
pushd cti-python-stix2
@ -209,9 +214,11 @@ jobs:
- name: Run tests
run: |
source $HOME/.poetry/env # enable poetry binary
./app/Vendor/bin/parallel-lint --exclude app/Lib/cakephp/ --exclude app/Vendor/ --exclude app/Lib/random_compat/ -e php,ctp app/
./app/Vendor/bin/phpunit app/Test/ComplexTypeToolTest.php
./app/Vendor/bin/phpunit app/Test/JSONConverterToolTest.php
./app/Vendor/bin/phpunit app/Test/CidrToolTest.php
# Ensure the perms of config files
sudo chown -R $USER:www-data `pwd`/app/Config

View File

@ -675,6 +675,7 @@ kaliSpaceSaver () {
echo "${RED}Not implement${NC}"
}
# FIXME: Kali now uses kali/kali instead of root/toor
# Because Kali is l33t we make sure we DO NOT run as root
kaliOnTheR0ckz () {
totalRoot=$(df -k | grep /$ |awk '{ print $2 }')
@ -776,6 +777,7 @@ installRNG () {
kaliUpgrade () {
debug "Running various Kali upgrade tasks"
checkAptLock
sudo DEBIAN_FRONTEND=noninteractive apt update
sudo DEBIAN_FRONTEND=noninteractive apt install --only-upgrade bash libc6 -y
sudo DEBIAN_FRONTEND=noninteractive apt autoremove -y
}
@ -1197,7 +1199,7 @@ installDepsPhp74 () {
libapache2-mod-php \
php php-cli \
php-dev \
php-json php-xml php-mysql php-opcache php-readline php-mbstring php-zip \
php-json php-xml php-mysql php7.4-opcache php-readline php-mbstring php-zip \
php-redis php-gnupg \
php-intl php-bcmath \
php-gd
@ -1559,6 +1561,7 @@ coreCAKE () {
# Various plugin sightings settings
$SUDO_WWW $RUN_PHP -- $CAKE Admin setSetting "Plugin.Sightings_policy" 0
$SUDO_WWW $RUN_PHP -- $CAKE Admin setSetting "Plugin.Sightings_anonymise" false
$SUDO_WWW $RUN_PHP -- $CAKE Admin setSetting "Plugin.Sightings_anonymise_as" 1
$SUDO_WWW $RUN_PHP -- $CAKE Admin setSetting "Plugin.Sightings_range" 365
$SUDO_WWW $RUN_PHP -- $CAKE Admin setSetting "Plugin.Sightings_sighting_db_enable" false
@ -1766,6 +1769,7 @@ mispmodules () {
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install -I -r REQUIREMENTS
sudo chgrp staff .
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install -I .
$SUDO_WWW ${PATH_TO_MISP}/venv/bin/pip install censys pyfaup
# Start misp-modules as a service
sudo cp /usr/local/src/misp-modules/etc/systemd/system/misp-modules.service /etc/systemd/system/
@ -2539,6 +2543,7 @@ mispmodulesRHEL () {
# pip install
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U -I -r REQUIREMENTS
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install -U .
$SUDO_WWW $PATH_TO_MISP/venv/bin/pip install pyfaup censys
sudo yum install rubygem-rouge rubygem-asciidoctor zbar-devel opencv-devel -y
echo "[Unit]
@ -2780,10 +2785,10 @@ installSupported () {
# Install PHP 7.2 Dependencies - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp72
elif [[ "$PHP_VER" == 7.3 ]]; then
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp73
elif [[ "$PHP_VER" == 7.4 ]]; then
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp74
elif [[ "$PHP_VER" == 7.0 ]]; then
# Install PHP 7.0 Dependencies - functionLocation('generic/supportFunctions.md')
@ -2885,7 +2890,7 @@ installSupported () {
# Main Kali Install function
installMISPonKali () {
# Kali might have a bug on installs where libc6 is not up to date, this forces bash and libc to update - functionLocation('')
# Kali might have a bug on installs where libc6 is not up to date, this forces bash and libc to update - functionLocation('generic/supportFunctions.md')
kaliUpgrade
# Set locale if not set - functionLocation('generic/supportFunctions.md')
@ -2894,8 +2899,8 @@ installMISPonKali () {
# Set Base URL - functionLocation('generic/supportFunctions.md')
setBaseURL
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
installDepsPhp73
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
installDepsPhp74
# Set custom Kali only variables and tweaks
space
@ -2913,12 +2918,12 @@ installMISPonKali () {
installCoreDeps
debug "Enabling redis and gnupg modules"
sudo phpenmod -v 7.3 redis
sudo phpenmod -v 7.3 gnupg
sudo phpenmod -v 7.4 redis
sudo phpenmod -v 7.4 gnupg
debug "Apache2 ops: dismod: status - dissite: 000-default enmod: ssl rewrite headers php7.3 ensite: default-ssl"
sudo a2dismod status
sudo a2enmod ssl rewrite headers php7.3
sudo a2enmod ssl rewrite headers php7.4
sudo a2dissite 000-default
sudo a2ensite default-ssl
@ -3021,26 +3026,18 @@ installMISPonKali () {
debug "Setting up database"
if [[ ! -e /var/lib/mysql/misp/users.ibd ]]; then
echo "
set timeout 10
spawn sudo mysql_secure_installation
expect \"Enter current password for root (enter for none):\"
send -- \"\r\"
expect \"Set root password?\"
send -- \"y\r\"
expect \"New password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Re-enter new password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Remove anonymous users?\"
send -- \"y\r\"
expect \"Disallow root login remotely?\"
send -- \"y\r\"
expect \"Remove test database and access to it?\"
send -- \"y\r\"
expect \"Reload privilege tables now?\"
send -- \"y\r\"
expect eof" | expect -f -
# Kill the anonymous users
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'localhost'"
# Because our hostname varies we'll use some Bash magic here.
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'$(hostname)'"
# Kill off the demo database
sudo mysql -h $DBHOST -e "DROP DATABASE IF EXISTS test"
# No root remote logins
sudo mysql -h $DBHOST -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
# Make sure that NOBODY can access the server without a password
sudo mysqladmin -h $DBHOST -u "${DBUSER_ADMIN}" password "${DBPASSWORD_ADMIN}"
# Make our changes take effect
sudo mysql -h $DBHOST -e "FLUSH PRIVILEGES"
sudo mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "CREATE DATABASE $DBNAME;"
sudo mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "GRANT USAGE ON *.* TO $DBUSER_MISP@localhost IDENTIFIED BY '$DBPASSWORD_MISP';"
@ -3291,9 +3288,7 @@ x86_64-debian-stretch
x86_64-debian-buster
x86_64-ubuntu-bionic
x86_64-ubuntu-focal
x86_64-kali-2020.1
x86_64-kali-2020.2
x86_64-kali-2020.3
x86_64-ubuntu-hirsute
x86_64-kali-2020.4
armv6l-raspbian-stretch
armv7l-raspbian-stretch
@ -3328,6 +3323,11 @@ if [[ "${FLAVOUR}" == "ubuntu" ]]; then
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installSupported PHP="7.4" && exit || exit
fi
if [[ "${RELEASE}" == "21.04" ]]; then
echo "Install on Ubuntu 21.04 LTS fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installSupported PHP="7.4" && exit || exit
fi
if [[ "${RELEASE}" == "18.10" ]]; then
echo "Install on Ubuntu 18.10 partially supported, bye."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"

View File

@ -1,5 +1,5 @@
; Generated by RHash v1.3.9 on 2021-01-15 at 16:07.48
; Generated by RHash v1.3.9 on 2021-02-15 at 12:01.57
; Written by Kravchenko Aleksey (Akademgorodok) - http://rhash.sf.net/
;
; 137197 16:07.48 2021-01-15 INSTALL.sh
INSTALL.sh AC931C9555B90E9C3B0935492DAA0E7EDC4B4394 E77AC1F6FA1B60AFAE910B86B59ACC5C33E2019D738B3E3380732FA51354D1AD C40E1D6E33EB14394C93E5C3FDFDC8DA66C2216AC0D22D1453578BD47AD052C84CB48EFDEA4F0769697A92A59FEA7E0F 8F5E59632C0B02F9CDAEE5B3B301697EA7ABFF8D1359673499689A4389A25D059625EBC2B650C114AD114A336ECA609A588FF6C6633FFDCE599F69A7717BD0F8
; 137749 12:01.57 2021-02-15 INSTALL.sh
INSTALL.sh 5C4651E28DAD85AFCB59E6914D8ACAB6E447BEB7 506B3B399D5B8EC140538054D9E78ABFA11A8AD45CE5E42AC77A72FB71762FDE 400AFBF6ACA765F314F4D044ABC28D3D94E38D6223F642E1BED3F8C7884CAA64BAA10647352E5BF94411DA8A6753D549 3AC6B5A002645E7F29547F1134BE3C744BFD3D1B253473702B9132E7CEC271474333407F7AA375996EAF9A9877E8E73A7D3C655DDC6E9C7A83F5DF37FA418FB6

View File

@ -1 +1 @@
ac931c9555b90e9c3b0935492daa0e7edc4b4394 INSTALL.sh
5c4651e28dad85afcb59e6914d8acab6e447beb7 INSTALL.sh

View File

@ -1 +1 @@
e77ac1f6fa1b60afae910b86b59acc5c33e2019d738b3e3380732fa51354d1ad INSTALL.sh
506b3b399d5b8ec140538054d9e78abfa11a8ad45ce5e42ac77a72fb71762fde INSTALL.sh

View File

@ -1 +1 @@
c40e1d6e33eb14394c93e5c3fdfdc8da66c2216ac0d22d1453578bd47ad052c84cb48efdea4f0769697a92a59fea7e0f INSTALL.sh
400afbf6aca765f314f4d044abc28d3d94e38d6223f642e1bed3f8c7884caa64baa10647352e5bf94411da8a6753d549 INSTALL.sh

View File

@ -1 +1 @@
8f5e59632c0b02f9cdaee5b3b301697ea7abff8d1359673499689a4389a25d059625ebc2b650c114ad114a336eca609a588ff6c6633ffdce599f69a7717bd0f8 INSTALL.sh
3ac6b5a002645e7f29547f1134be3c744bfd3d1b253473702b9132e7cec271474333407f7aa375996eaf9a9877e8e73a7d3c655ddc6e9c7a83f5df37fa418fb6 INSTALL.sh

View File

@ -284,10 +284,10 @@ installSupported () {
# Install PHP 7.2 Dependencies - functionLocation('INSTALL.ubuntu1804.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp72
elif [[ "$PHP_VER" == 7.3 ]]; then
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp73
elif [[ "$PHP_VER" == 7.4 ]]; then
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
[[ -n $CORE ]] || [[ -n $ALL ]] && installDepsPhp74
elif [[ "$PHP_VER" == 7.0 ]]; then
# Install PHP 7.0 Dependencies - functionLocation('generic/supportFunctions.md')
@ -389,7 +389,7 @@ installSupported () {
# Main Kali Install function
installMISPonKali () {
# Kali might have a bug on installs where libc6 is not up to date, this forces bash and libc to update - functionLocation('')
# Kali might have a bug on installs where libc6 is not up to date, this forces bash and libc to update - functionLocation('generic/supportFunctions.md')
kaliUpgrade
# Set locale if not set - functionLocation('generic/supportFunctions.md')
@ -398,8 +398,8 @@ installMISPonKali () {
# Set Base URL - functionLocation('generic/supportFunctions.md')
setBaseURL
# Install PHP 7.3 Dependencies - functionLocation('generic/supportFunctions.md')
installDepsPhp73
# Install PHP 7.4 Dependencies - functionLocation('INSTALL.ubuntu2004.md')
installDepsPhp74
# Set custom Kali only variables and tweaks
space
@ -417,12 +417,12 @@ installMISPonKali () {
installCoreDeps
debug "Enabling redis and gnupg modules"
sudo phpenmod -v 7.3 redis
sudo phpenmod -v 7.3 gnupg
sudo phpenmod -v 7.4 redis
sudo phpenmod -v 7.4 gnupg
debug "Apache2 ops: dismod: status - dissite: 000-default enmod: ssl rewrite headers php7.3 ensite: default-ssl"
sudo a2dismod status
sudo a2enmod ssl rewrite headers php7.3
sudo a2enmod ssl rewrite headers php7.4
sudo a2dissite 000-default
sudo a2ensite default-ssl
@ -525,26 +525,18 @@ installMISPonKali () {
debug "Setting up database"
if [[ ! -e /var/lib/mysql/misp/users.ibd ]]; then
echo "
set timeout 10
spawn sudo mysql_secure_installation
expect \"Enter current password for root (enter for none):\"
send -- \"\r\"
expect \"Set root password?\"
send -- \"y\r\"
expect \"New password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Re-enter new password:\"
send -- \"${DBPASSWORD_ADMIN}\r\"
expect \"Remove anonymous users?\"
send -- \"y\r\"
expect \"Disallow root login remotely?\"
send -- \"y\r\"
expect \"Remove test database and access to it?\"
send -- \"y\r\"
expect \"Reload privilege tables now?\"
send -- \"y\r\"
expect eof" | expect -f -
# Kill the anonymous users
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'localhost'"
# Because our hostname varies we'll use some Bash magic here.
sudo mysql -h $DBHOST -e "DROP USER IF EXISTS ''@'$(hostname)'"
# Kill off the demo database
sudo mysql -h $DBHOST -e "DROP DATABASE IF EXISTS test"
# No root remote logins
sudo mysql -h $DBHOST -e "DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')"
# Make sure that NOBODY can access the server without a password
sudo mysqladmin -h $DBHOST -u "${DBUSER_ADMIN}" password "${DBPASSWORD_ADMIN}"
# Make our changes take effect
sudo mysql -h $DBHOST -e "FLUSH PRIVILEGES"
sudo mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "CREATE DATABASE $DBNAME;"
sudo mysql -u $DBUSER_ADMIN -p$DBPASSWORD_ADMIN -e "GRANT USAGE ON *.* TO $DBUSER_MISP@localhost IDENTIFIED BY '$DBPASSWORD_MISP';"
@ -795,9 +787,7 @@ x86_64-debian-stretch
x86_64-debian-buster
x86_64-ubuntu-bionic
x86_64-ubuntu-focal
x86_64-kali-2020.1
x86_64-kali-2020.2
x86_64-kali-2020.3
x86_64-ubuntu-hirsute
x86_64-kali-2020.4
armv6l-raspbian-stretch
armv7l-raspbian-stretch
@ -832,6 +822,11 @@ if [[ "${FLAVOUR}" == "ubuntu" ]]; then
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installSupported PHP="7.4" && exit || exit
fi
if [[ "${RELEASE}" == "21.04" ]]; then
echo "Install on Ubuntu 21.04 LTS fully supported."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"
installSupported PHP="7.4" && exit || exit
fi
if [[ "${RELEASE}" == "18.10" ]]; then
echo "Install on Ubuntu 18.10 partially supported, bye."
echo "Please report bugs/issues here: https://github.com/MISP/MISP/issues"

2
PyMISP

@ -1 +1 @@
Subproject commit 5b97b7d0158906cd0f646a7273a3ca5b1828cd15
Subproject commit 9316420dc028a1ffc541986fc08793e669f2165e

View File

@ -1 +1 @@
{"major":2, "minor":4, "hotfix":137}
{"major":2, "minor":4, "hotfix":139}

View File

@ -214,19 +214,24 @@ class AdminShell extends AppShell
if (empty($user)) {
echo 'User with ID: ' . $userId . ' not found' . PHP_EOL;
$result = $this->ObjectTemplate->update();
if ($result) {
echo 'Object templates updated' . PHP_EOL;
} else {
echo 'Could not update object templates' . PHP_EOL;
}
} else {
$result = $this->ObjectTemplate->update($user, false,false);
if ($result) {
echo 'Object templates updated' . PHP_EOL;
} else {
echo 'Could not update object templates' . PHP_EOL;
}
$successes = count(!empty($result['success']) ? $result['success'] : []);
$fails = count(!empty($result['fails']) ? $result['fails'] : []);
$message = '';
if ($successes == 0 && $fails == 0) {
$message = __('All object templates are up to date already.');
} elseif ($successes == 0 && $fails > 0) {
$message = __('Could not update any of the object templates.');
} elseif ($successes > 0 ) {
$message = __('Successfully updated %s object templates.', $successes);
if ($fails != 0) {
$message .= __(' However, could not update %s object templates.', $fails);
}
}
echo $message . PHP_EOL;
}
}

View File

@ -35,10 +35,7 @@ class EventShell extends AppShell
public function import()
{
list($userId, $path) = $this->args;
$user = $this->User->getAuthUser($userId);
if (empty($user)) {
$this->error("User with ID $userId does not exists.");
}
$user = $this->getUser($userId);
if (!file_exists($path)) {
$this->error("File '$path' does not exists.");
@ -113,7 +110,7 @@ class EventShell extends AppShell
$timeStart = time();
$userId = $this->args[0];
$id = $this->args[1];
$user = $this->User->getAuthUser($userId);
$user = $this->getUser($userId);
$this->Job->id = $id;
$export_type = $this->args[2];
file_put_contents('/tmp/test', $export_type);
@ -204,10 +201,7 @@ class EventShell extends AppShell
$jobId = $this->args[1];
$eventId = $this->args[2];
$oldpublish = $this->args[3];
$user = $this->User->getUserById($userId);
if (empty($user)) {
die("Invalid user ID '$userId' provided.");
}
$user = $this->getUser($userId);
$this->Event->sendAlertEmail($eventId, $user, $oldpublish, $jobId);
}
@ -220,10 +214,7 @@ class EventShell extends AppShell
$userId = $this->args[3];
$processId = $this->args[4];
$user = $this->User->getUserById($userId);
if (empty($user)) {
die("Invalid user ID '$userId' provided.");
}
$user = $this->getUser($userId);
$result = $this->Event->sendContactEmail($id, $message, $all, $user);
$this->Job->saveStatus($processId, $result);
}
@ -305,10 +296,7 @@ class EventShell extends AppShell
$passAlong = $this->args[1];
$jobId = $this->args[2];
$userId = $this->args[3];
$user = $this->User->getAuthUser($userId);
if (empty($user)) {
die("Invalid user ID '$userId' provided.");
}
$user = $this->getUser($userId);
$job = $this->Job->read(null, $jobId);
$this->Event->Behaviors->unload('SysLogLogable.SysLogLogable');
$result = $this->Event->publish($id, $passAlong);
@ -332,10 +320,7 @@ class EventShell extends AppShell
$passAlong = $this->args[1];
$jobId = $this->args[2];
$userId = $this->args[3];
$user = $this->User->getAuthUser($userId);
if (empty($user)) {
die("Invalid user ID '$userId' provided.");
}
$user = $this->getUser($userId);
$job = $this->Job->read(null, $jobId);
$this->Event->Behaviors->unload('SysLogLogable.SysLogLogable');
$result = $this->Event->publish_sightings($id, $passAlong);
@ -359,7 +344,7 @@ class EventShell extends AppShell
$jobId = $this->args[1];
$userId = $this->args[2];
$passAlong = $this->args[3];
$user = $this->User->getAuthUser($userId);
$user = $this->getUser($userId);
$job = $this->Job->read(null, $jobId);
$this->GalaxyCluster = ClassRegistry::init('GalaxyCluster');
$result = $this->GalaxyCluster->publish($clusterId, $passAlong=$passAlong);
@ -383,8 +368,7 @@ class EventShell extends AppShell
die('Usage: ' . $this->Server->command_line_functions['enrichment'] . PHP_EOL);
}
$userId = $this->args[0];
$user = $this->User->getAuthUser($userId);
if (empty($user)) die('Invalid user.');
$user = $this->getUser($userId);
$eventId = $this->args[1];
$modulesRaw = $this->args[2];
try {
@ -484,4 +468,17 @@ class EventShell extends AppShell
$job['Job']['message'] = __('Recovery complete. Event #%s recovered, using %s log entries.', $id, $result);
$this->Job->save($job);
}
/**
* @param int $userId
* @return array
*/
private function getUser($userId)
{
$user = $this->User->getAuthUser($userId);
if (empty($user)) {
$this->error("User with ID $userId does not exists.");
}
return $user;
}
}

View File

@ -25,8 +25,8 @@ class AppController extends Controller
public $helpers = array('OrgImg', 'FontAwesome', 'UserName', 'DataPathCollector');
private $__queryVersion = '122';
public $pyMispVersion = '2.4.137';
private $__queryVersion = '125';
public $pyMispVersion = '2.4.138';
public $phpmin = '7.2';
public $phprec = '7.4';
public $phptoonew = '8.0';

View File

@ -998,6 +998,7 @@ class AttributesController extends AppController
'includeAllTags' => false,
'includeAttributeUuid' => true,
'flatten' => true,
'deleted' => [0, 1]
);
if ($this->_isRest()) {
@ -1505,7 +1506,6 @@ class AttributesController extends AppController
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => $paramArray,
'ordered_url_params' => @compact($paramArray),
'additional_delimiters' => PHP_EOL
);
$exception = false;

View File

@ -346,7 +346,9 @@ class ACLComponent extends Component
'view' => array('*'),
),
'galaxyElements' => array(
'index' => array('*')
'delete' => array('perm_galaxy_editor'),
'flattenJson' => array('perm_galaxy_editor'),
'index' => array('*'),
),
'jobs' => array(
'cache' => array('*'),
@ -412,6 +414,7 @@ class ACLComponent extends Component
'edit' => array('perm_object_template'),
'delete' => array('perm_object_template'),
'getToggleField' => array(),
'getRaw' => array('perm_object_template'),
'objectChoice' => array('*'),
'objectMetaChoice' => array('perm_add'),
'view' => array('*'),
@ -542,6 +545,7 @@ class ACLComponent extends Component
'generateCorrelation' => array(),
'index' => array('*'),
'view' => array('*'),
'viewPicture' => array('*'),
),
'sharingGroups' => array(
'add' => array('perm_sharing_group'),

View File

@ -532,7 +532,9 @@ class RestResponseComponent extends Component
$response['sql_dump'] = $this->Log->getDataSource()->getLog(false, false);
}
}
$response = json_encode($response, JSON_PRETTY_PRINT);
// Do not pretty print response for automatic tools
$flags = $this->isAutomaticTool() ? JSON_UNESCAPED_UNICODE : JSON_PRETTY_PRINT;
$response = json_encode($response, $flags);
} else {
if ($dumpSql) {
$this->Log = ClassRegistry::init('Log');
@ -582,6 +584,16 @@ class RestResponseComponent extends Component
return $cakeResponse;
}
/**
* Detect if request comes from automatic tool, like other MISP instance or PyMISP
* @return bool
*/
public function isAutomaticTool()
{
$userAgent = CakeRequest::header('User-Agent');
return $userAgent && (substr($userAgent, 0, 6) === 'PyMISP' || substr($userAgent, 0, 4) === 'MISP');
}
private function __generateURL($action, $controller, $id)
{
$controller = Inflector::underscore(Inflector::pluralize($controller));
@ -1806,8 +1818,6 @@ class RestResponseComponent extends Component
private function __overwriteReturnFormat($scope, $action, &$field) {
switch($scope) {
case "Attribute":
$field['values'] = array_keys(ClassRegistry::init($scope)->validFormats);
break;
case "Event":
$field['values'] = array_keys(ClassRegistry::init($scope)->validFormats);
break;

View File

@ -1,6 +1,9 @@
<?php
App::uses('AppController', 'Controller');
/**
* @property Dashboard $Dashboard
*/
class DashboardsController extends AppController
{
public $components = array('Session', 'RequestHandler');
@ -147,47 +150,50 @@ class DashboardsController extends AppController
public function renderWidget($widget_id, $force = false)
{
if ($this->request->is('post')) {
if (empty($this->request->data['data'])) {
$this->request->data = array('data' => $this->request->data);
}
if (empty($this->request->data['data'])) {
throw new MethodNotAllowedException(__('You need to specify the widget to use along with the configuration.'));
}
$value = $this->request->data['data'];
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $value['widget']);
$this->layout = false;
$this->set('title', $dashboardWidget->title);
$redis = $this->Dashboard->setupRedis();
$org_scope = $this->_isSiteAdmin() ? 0 : $this->Auth->user('org_id');
$lookup_hash = hash('sha256', $value['widget'] . $value['config']);
$data = $redis->get('misp:dashboard:' . $org_scope . ':' . $lookup_hash);
if (!isset($dashboardWidget->cacheLifetime)) {
$dashboardWidget->cacheLifetime = false;
}
if (empty($dashboardWidget->cacheLifetime) || empty($data)) {
$data = $dashboardWidget->handler($this->Auth->user(), json_decode($value['config'], true));
if (!empty($dashboardWidget->cacheLifetime)) {
$redis->set('misp:dashboard:' . $org_scope . ':' . $lookup_hash, json_encode(array('data' => $data)));
$redis->expire('misp:dashboard:' . $org_scope . ':' . $lookup_hash, $dashboardWidget->cacheLifetime);
}
} else {
$data = json_decode($data, true)['data'];
}
$valueConfig = json_decode($value['config'], true);
$config = array(
'render' => $dashboardWidget->render,
'autoRefreshDelay' => empty($dashboardWidget->autoRefreshDelay) ? false : $dashboardWidget->autoRefreshDelay,
'widget_config' => empty($valueConfig['widget_config']) ? array() : $valueConfig['widget_config']
);
$this->set('widget_id', $widget_id);
$this->set('data', $data);
$this->set('config', $config);
$this->render('widget_loader');
} else {
if (!$this->request->is('post')) {
throw new MethodNotAllowedException(__('This endpoint can only be reached via POST requests.'));
}
@session_write_close(); // allow concurrent AJAX requests (session hold lock by default)
if (empty($this->request->data['data'])) {
$this->request->data = array('data' => $this->request->data);
}
if (empty($this->request->data['data'])) {
throw new MethodNotAllowedException(__('You need to specify the widget to use along with the configuration.'));
}
$value = $this->request->data['data'];
$valueConfig = json_decode($value['config'], true);
$dashboardWidget = $this->Dashboard->loadWidget($this->Auth->user(), $value['widget']);
$redis = $this->Dashboard->setupRedis();
$org_scope = $this->_isSiteAdmin() ? 0 : $this->Auth->user('org_id');
$lookup_hash = hash('sha256', $value['widget'] . $value['config']);
$cacheKey = 'misp:dashboard:' . $org_scope . ':' . $lookup_hash;
$data = $redis->get($cacheKey);
if (!isset($dashboardWidget->cacheLifetime)) {
$dashboardWidget->cacheLifetime = false;
}
if (empty($dashboardWidget->cacheLifetime) || empty($data)) {
$data = $dashboardWidget->handler($this->Auth->user(), $valueConfig);
if (!empty($dashboardWidget->cacheLifetime)) {
$redis->setex($cacheKey, $dashboardWidget->cacheLifetime, json_encode(array('data' => $data)));
}
} else {
$data = json_decode($data, true)['data'];
}
$config = array(
'render' => $dashboardWidget->render,
'autoRefreshDelay' => empty($dashboardWidget->autoRefreshDelay) ? false : $dashboardWidget->autoRefreshDelay,
'widget_config' => empty($valueConfig['widget_config']) ? array() : $valueConfig['widget_config']
);
$this->layout = false;
$this->set('title', $dashboardWidget->title);
$this->set('widget_id', $widget_id);
$this->set('data', $data);
$this->set('config', $config);
$this->render('widget_loader');
}
public function import()
@ -392,7 +398,7 @@ class DashboardsController extends AppController
$element['User']['email'] = '';
}
}
$this->set('passedArgs', $this->passedArgs);
$this->set('passedArgs', json_encode($this->passedArgs));
$this->set('data', $data);
}
}

View File

@ -124,12 +124,14 @@ class EventReportsController extends AppController
{
$report = $this->EventReport->fetchIfAuthorized($this->Auth->user(), $id, 'delete', $throwErrors=true, $full=false);
if ($this->request->is('post')) {
$errors = $this->EventReport->deleteReport($this->Auth->user(), $report, $hard=$hard);
if (!empty($this->request->data['hard'])) {
$hard = true;
}
$errors = $this->EventReport->deleteReport($this->Auth->user(), $report, $hard);
$redirectTarget = $this->referer();
if (empty($errors)) {
$successMessage = __('Event Report %s %s deleted', $id, $hard ? __('hard') : __('soft'));
$report = $hard ? null : $this->EventReport->simpleFetchById($this->Auth->user(), $id);
return $this->__getSuccessResponseBasedOnContext($successMessage, $report, 'delete', $id, $redirectTarget);
return $this->__getSuccessResponseBasedOnContext($successMessage, null, 'delete', $id, $redirectTarget);
} else {
$errorMessage = __('Event Report %s could not be %s deleted.%sReasons: %s', $id, $hard ? __('hard') : __('soft'), PHP_EOL, json_encode($errors));
return $this->__getFailResponseBasedOnContext($errorMessage, array(), 'edit', $id, $redirectTarget);
@ -153,8 +155,7 @@ class EventReportsController extends AppController
$redirectTarget = $this->referer();
if (empty($errors)) {
$successMessage = __('Event Report %s restored', $id);
$report = $this->EventReport->simpleFetchById($this->Auth->user(), $id);
return $this->__getSuccessResponseBasedOnContext($successMessage, $report, 'restore', $id, $redirectTarget);
return $this->__getSuccessResponseBasedOnContext($successMessage, null, 'restore', $id, $redirectTarget);
} else {
$errorMessage = __('Event Report %s could not be %s restored.%sReasons: %s', $id, PHP_EOL, json_encode($errors));
return $this->__getFailResponseBasedOnContext($errorMessage, array(), 'restore', $id, $redirectTarget);

View File

@ -1612,17 +1612,17 @@ class EventsController extends AppController
}
if ($this->_isRest()) {
$this->set('event', $event);
} else {
$this->set('deleted', isset($deleted) ? ($deleted == 2 ? 0 : 1) : 0);
$this->set('includeRelatedTags', (!empty($this->params['named']['includeRelatedTags'])) ? 1 : 0);
$this->set('includeDecayScore', (!empty($this->params['named']['includeDecayScore'])) ? 1 : 0);
if ($this->_isSiteAdmin() && $event['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
$this->Flash->info(__('You are currently logged in as a site administrator and about to edit an event not belonging to your organisation. This goes against the sharing model of MISP. Use a normal user account for day to day work.'));
}
$this->__viewUI($event, $continue, $fromEvent);
return $this->__restResponse($event);
}
$this->set('deleted', isset($deleted) ? ($deleted == 2 ? 0 : 1) : 0);
$this->set('includeRelatedTags', (!empty($this->params['named']['includeRelatedTags'])) ? 1 : 0);
$this->set('includeDecayScore', (!empty($this->params['named']['includeDecayScore'])) ? 1 : 0);
if ($this->_isSiteAdmin() && $event['Event']['orgc_id'] !== $this->Auth->user('org_id')) {
$this->Flash->info(__('You are currently logged in as a site administrator and about to edit an event not belonging to your organisation. This goes against the sharing model of MISP. Use a normal user account for day to day work.'));
}
$this->__viewUI($event, $continue, $fromEvent);
}
private function __startPivoting($id, $info, $date)
@ -1741,6 +1741,9 @@ class EventsController extends AppController
// search for all attributes in object
foreach ($event['Object'] as $k => $object) {
if ($this->__valueInFieldAttribute($object, ['id', 'uuid', 'name', 'comment'], $searchFor)) {
continue;
}
foreach ($object['Attribute'] as $k2 => $attribute) {
if (!$this->__valueInFieldAttribute($attribute, $filterValue, $searchFor)) {
unset($event['Object'][$k]['Attribute'][$k2]);
@ -1914,9 +1917,7 @@ class EventsController extends AppController
if (!empty($validationErrors)) {
$event['errors'] = $validationErrors;
}
$this->set('event', $event);
$this->render('view');
return true;
return $this->__restResponse($event);
} else {
// redirect to the view of the newly created event
$this->Flash->success(__('The event has been saved'));
@ -2168,9 +2169,12 @@ class EventsController extends AppController
if (empty($source_event)) {
throw new NotFoundException(__('Invalid source event.'));
}
$recovered_uuids = [];
foreach ($source_event[0]['Attribute'] as &$attribute) {
unset($attribute['id']);
$originalUUID = $attribute['uuid'];
$attribute['uuid'] = CakeText::uuid();
$recovered_uuids[$originalUUID] = $attribute['uuid'];
unset($attribute['ShadowAttribute']);
$attribute['Tag'] = [];
foreach ($attribute['AttributeTag'] as $aT) {
@ -2181,10 +2185,14 @@ class EventsController extends AppController
}
foreach ($source_event[0]['Object'] as &$object) {
unset($object['id']);
$originalUUID = $object['uuid'];
$object['uuid'] = CakeText::uuid();
$recovered_uuids[$originalUUID] = $object['uuid'];
foreach ($object['Attribute'] as &$attribute) {
unset($attribute['id']);
$originalUUID = $attribute['uuid'];
$attribute['uuid'] = CakeText::uuid();
$recovered_uuids[$originalUUID] = $attribute['uuid'];
unset($attribute['ShadowAttribute']);
$attribute['Tag'] = [];
foreach ($attribute['AttributeTag'] as $aT) {
@ -2194,21 +2202,39 @@ class EventsController extends AppController
unset($attribute['AttributeTag']);
}
}
foreach ($source_event[0]['Object'] as &$object) {
foreach ($object['ObjectReference'] as &$reference) {
if (isset($recovered_uuids[$object['uuid']])) {
$reference['object_uuid'] = $recovered_uuids[$object['uuid']];
}
if (isset($recovered_uuids[$reference['referenced_uuid']])) {
$reference['referenced_uuid'] = $recovered_uuids[$reference['referenced_uuid']];
}
}
}
foreach ($source_event[0]['EventReport'] as &$report) {
unset($report['id'], $report['event_id']);
$report['uuid'] = CakeText::uuid();
}
$results = [
'results' => [
'Object' => $source_event[0]['Object'],
'Attribute' => $source_event[0]['Attribute']
'Attribute' => $source_event[0]['Attribute'],
'EventReport' => $source_event[0]['EventReport']
]
];
if ($this->_isRest()) {
$this->loadModel('Log');
$save_results = ['attributes' => 0, 'objects' => 0];
$save_results = ['attributes' => 0, 'objects' => 0, 'eventReports' => 0];
foreach ($results['results']['Attribute'] as $attribute) {
$this->Event->Attribute->captureAttribute($attribute, $target_id, $this->Auth->user(), false, $this->Log);
}
foreach ($results['results']['Object'] as $object) {
$this->Event->Object->captureObject($object, $target_id, $this->Auth->user(), $this->Log);
}
foreach ($results['results']['EventReport'] as $report) {
$this->Event->EventReport->captureReport($this->Auth->user(), $report, $target_id);
}
$event = $this->Event->fetchEvent(
$this->Auth->user(),
[
@ -2279,9 +2305,7 @@ class EventsController extends AppController
$metadata = $this->request->param('named.metadata');
$results = $this->Event->fetchEvent($this->Auth->user(), ['eventid' => $id, 'metadata' => $metadata]);
$event = $results[0];
$this->set('event', $event);
$this->render('view');
return true;
return $this->__restResponse($event);
} else {
$message = 'Error';
if ($this->_isRest()) {
@ -3699,9 +3723,6 @@ class EventsController extends AppController
public function filterEventIdsForPush()
{
if (!$this->userRole['perm_sync']) {
throw new MethodNotAllowedException(__('You do not have the permission to do that.'));
}
if ($this->request->is('post')) {
$incomingIDs = array();
$incomingEvents = array();
@ -3714,16 +3735,16 @@ class EventsController extends AppController
'recursive' => -1,
'fields' => array('Event.uuid', 'Event.timestamp', 'Event.locked'),
));
foreach ($events as $k => $v) {
if ($v['Event']['timestamp'] >= $incomingEvents[$v['Event']['uuid']]) {
unset($incomingEvents[$v['Event']['uuid']]);
foreach ($events as $event) {
if ($event['Event']['timestamp'] >= $incomingEvents[$event['Event']['uuid']]) {
unset($incomingEvents[$event['Event']['uuid']]);
continue;
}
if ($v['Event']['locked'] == 0) {
unset($incomingEvents[$v['Event']['uuid']]);
if ($event['Event']['locked'] == 0) {
unset($incomingEvents[$event['Event']['uuid']]);
}
}
$this->set('result', array_keys($incomingEvents));
return $this->RestResponse->viewData(array_keys($incomingEvents), $this->response->type());
}
}
@ -4506,16 +4527,23 @@ class EventsController extends AppController
if ($scope == 'event') {
$eventId = $scope_id;
} elseif ($scope == 'attribute') {
$attribute = $this->Event->Attribute->fetchAttributes($this->Auth->user(), array(
'conditions' => array('Attribute.id' => $scope_id),
'fields' => array('event_id'),
'flatten' => 1,
));
if (empty($attribute)) {
throw new Exception("Invalid Attribute.");
if ($scope_id == 'selected') {
if (empty($this->params['named']['eventid'])) {
throw new Exception("Invalid Event.");
}
$eventId = $this->params['named']['eventid'];
} else {
$attribute = $this->Event->Attribute->fetchAttributes($this->Auth->user(), array(
'conditions' => array('Attribute.id' => $scope_id),
'fields' => array('event_id'),
'flatten' => 1,
));
if (empty($attribute)) {
throw new Exception("Invalid Attribute.");
}
$attribute = $attribute[0];
$eventId = $attribute['Attribute']['event_id'];
}
$attribute = $attribute[0];
$eventId = $attribute['Attribute']['event_id'];
} elseif ($scope == 'tag_collection') {
$eventId = 0; // no event_id for tag_collection, consider all events
} else {
@ -5141,7 +5169,7 @@ class EventsController extends AppController
if ($this->request->is('Post')) {
if (Configure::read('Plugin.ZeroMQ_enable')) {
$pubSubTool = $this->Event->getPubSubTool();
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id));
$event = $this->Event->fetchEvent($this->Auth->user(), array('eventid' => $id, 'includeAllTags' => true));
if (!empty($event)) {
$pubSubTool->publishEvent($event[0]);
$success = 1;
@ -5188,7 +5216,7 @@ class EventsController extends AppController
$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);
$params = array('eventid' => $id, 'includeAllTags' => true);
if (Configure::read('Plugin.Kafka_include_attachments')) {
$params['includeAttachments'] = 1;
}
@ -5681,4 +5709,37 @@ class EventsController extends AppController
}
return $this->RestResponse->viewData($allConflicts);
}
/**
* @param array $event
* @return CakeResponseTmp
* @throws Exception
*/
private function __restResponse(array $event)
{
$tmpFile = new TmpFileTool();
if ($this->request->is('json')) {
App::uses('JSONConverterTool', 'Tools');
$converter = new JSONConverterTool();
if ($this->RestResponse->isAutomaticTool()) {
foreach ($converter->streamConvert($event) as $part) {
$tmpFile->write($part);
}
} else {
$tmpFile->write($converter->convert($event));
}
$format = 'json';
} elseif ($this->request->is('xml')) {
App::uses('XMLConverterTool', 'Tools');
$converter = new XMLConverterTool();
foreach ($converter->frameCollection($converter->convert($event)) as $chunk) {
$tmpFile->write($chunk);
}
$format = 'xml';
} else {
throw new Exception("Invalid format, only JSON or XML is supported.");
}
return $this->RestResponse->viewData($tmpFile, $format, false, true);
}
}

View File

@ -267,6 +267,7 @@ class GalaxiesController extends AppController
{
$mitreAttackGalaxyId = $this->Galaxy->getMitreAttackGalaxyId();
$local = !empty($this->params['named']['local']) ? $this->params['named']['local'] : '0';
$eventid = !empty($this->params['named']['eventid']) ? $this->params['named']['eventid'] : '0';
$conditions = $namespace === '0' ? array() : array('namespace' => $namespace);
$galaxies = $this->Galaxy->find('all', array(
'recursive' => -1,
@ -278,14 +279,14 @@ class GalaxiesController extends AppController
$items = array(
array(
'name' => __('All clusters'),
'value' => $this->baseurl . "/galaxies/selectCluster/" . h($target_id) . '/' . h($target_type) . '/0'. '/local:' . $local
'value' => $this->baseurl . "/galaxies/selectCluster/" . h($target_id) . '/' . h($target_type) . '/0'. '/local:' . $local . '/eventid:' . $eventid
)
);
foreach ($galaxies as $galaxy) {
if (!isset($galaxy['Galaxy']['kill_chain_order']) || $noGalaxyMatrix) {
$items[] = array(
'name' => h($galaxy['Galaxy']['name']),
'value' => $this->baseurl . "/galaxies/selectCluster/" . $target_id . '/' . $target_type . '/' . $galaxy['Galaxy']['id'] . '/local:' . $local,
'value' => $this->baseurl . "/galaxies/selectCluster/" . $target_id . '/' . $target_type . '/' . $galaxy['Galaxy']['id'] . '/local:' . $local . '/eventid:' . $eventid,
'template' => array(
'preIcon' => 'fa-' . $galaxy['Galaxy']['icon'],
'name' => $galaxy['Galaxy']['name'],
@ -296,11 +297,12 @@ class GalaxiesController extends AppController
$param = array(
'name' => $galaxy['Galaxy']['name'],
'functionName' => sprintf(
"getMatrixPopup('%s', '%s', '%s/local:%s')",
"getMatrixPopup('%s', '%s', '%s/local:%s/eventid:%s')",
$target_type,
$target_id,
$galaxy['Galaxy']['id'],
$local
$local,
$eventid
),
'isPill' => true,
'isMatrix' => true
@ -325,15 +327,17 @@ class GalaxiesController extends AppController
'order' => array('namespace asc')
));
$local = !empty($this->params['named']['local']) ? '1' : '0';
$eventid = !empty($this->params['named']['eventid']) ? $this->params['named']['eventid'] : '0';
$items = array();
$noGalaxyMatrix = $noGalaxyMatrix ? '1' : '0';
$items[] = array(
'name' => __('All namespaces'),
'value' => $this->baseurl . "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/0' . '/' . $noGalaxyMatrix . '/local:' . $local
'value' => $this->baseurl . "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/0' . '/' . $noGalaxyMatrix . '/local:' . $local . '/eventid:' . $eventid
);
foreach ($namespaces as $namespace) {
$items[] = array(
'name' => $namespace,
'value' => $this->baseurl . "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/' . $namespace . '/' . $noGalaxyMatrix . '/local:' . $local
'value' => $this->baseurl . "/galaxies/selectGalaxy/" . $target_id . '/' . $target_type . '/' . $namespace . '/' . $noGalaxyMatrix . '/local:' . $local . '/eventid:' . $eventid
);
}

View File

@ -56,7 +56,7 @@ class GalaxyClustersController extends AppController
$contextConditions['GalaxyCluster.deleted'] = true;
}
$this->set('passedArgsArray', array('context' => $filters['context'], 'searchall' => isset($filters['searchall']) ? $filters['searchall'] : ''));
$this->set('passedArgs', json_encode(array('context' => $filters['context'], 'searchall' => isset($filters['searchall']) ? $filters['searchall'] : '')));
$this->set('context', $filters['context']);
$searchConditions = array();
if (empty($filters['searchall'])) {
@ -972,7 +972,7 @@ class GalaxyClustersController extends AppController
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException('This function can only be reached via AJAX.');
}
$cluster = $this->GalaxyCluster->fetchIfAuthorized($this->Auth->user(), $id, 'view', $throwErrors=true, $full=true);
$cluster = $this->GalaxyCluster->fetchIfAuthorized($this->Auth->user(), $id, 'view', true, true);
$existingRelations = $this->GalaxyCluster->GalaxyClusterRelation->getExistingRelationships();
$cluster = $this->GalaxyCluster->attachClusterToRelations($this->Auth->user(), $cluster);
@ -983,12 +983,8 @@ class GalaxyClustersController extends AppController
$this->set('existingRelations', $existingRelations);
$this->set('cluster', $cluster);
$relations = $this->GalaxyCluster->GalaxyClusterRelation->fetchRelations($this->Auth->user(), array(
'conditions' => array(
'GalaxyClusterRelation.galaxy_cluster_uuid' => $cluster['GalaxyCluster']['uuid']
),
'contain' => array('SharingGroup', 'TargetCluster', 'GalaxyClusterRelationTag' => array('Tag'))
));
$relations = $cluster['GalaxyCluster']['GalaxyClusterRelation'];
$this->set('passedArgs', json_encode([]));
$this->set('relations', $relations);
$this->set('tree', $tree);
$this->loadModel('Attribute');

View File

@ -16,14 +16,102 @@ class GalaxyElementsController extends AppController
public function index($clusterId)
{
$filters = $this->IndexFilter->harvestParameters(array('context', 'searchall'));
$aclConditions = $this->GalaxyElement->buildClusterConditions($this->Auth->user(), $clusterId);
$this->paginate['conditions'] = [$aclConditions];
if (empty($filters['context'])) {
$filters['context'] = 'all';
}
$searchConditions = array();
if (empty($filters['searchall'])) {
$filters['searchall'] = '';
}
if (strlen($filters['searchall']) > 0) {
$searchall = '%' . strtolower($filters['searchall']) . '%';
$searchConditions = array(
'OR' => array(
'LOWER(GalaxyElement.key) LIKE' => $searchall,
'LOWER(GalaxyElement.value) LIKE' => $searchall,
),
);
}
$this->paginate['conditions'] = ['AND' => [$aclConditions, $searchConditions]];
$this->paginate['contain'] = ['GalaxyCluster' => ['fields' => ['id', 'distribution', 'org_id']]];
$clusters = $this->paginate();
$this->set('list', $clusters);
$elements = $this->paginate();
$this->set('elements', $elements);
$this->set('clusterId', $clusterId);
$this->set('context', $filters['context']);
$this->set('passedArgs', json_encode([
'context' => $filters['context'],
'searchall' => isset($filters['searchall']) ? $filters['searchall'] : ''
]));
$cluster = $this->GalaxyElement->GalaxyCluster->fetchIfAuthorized($this->Auth->user(), $clusterId, array('edit', 'delete'), false, false);
$canModify = !empty($cluster['authorized']);
$canModify = true;
$this->set('canModify', $canModify);
if ($filters['context'] == 'JSONView') {
$expanded = $this->GalaxyElement->getExpandedJSONFromElements($elements);
$this->set('JSONElements', $expanded);
}
if ($this->request->is('ajax')) {
$this->layout = 'ajax';
$this->render('ajax/index');
}
}
public function delete($elementId)
{
$element = $this->GalaxyElement->find('first', array('conditions' => array('GalaxyElement.id' => $elementId)));
if (empty($element)) {
throw new Exception(__('Element not found'));
}
$this->set('element', $element);
$clusterId = $element['GalaxyElement']['galaxy_cluster_id'];
$cluster = $this->GalaxyElement->GalaxyCluster->fetchIfAuthorized($this->Auth->user(), $clusterId, array('edit'), true, false);
if ($this->request->is('post')) {
$deleteResult = $this->GalaxyElement->delete($elementId);
if ($deleteResult) {
$this->GalaxyElement->GalaxyCluster->editCluster($this->Auth->user(), $cluster, [], false);
$message = __('Galaxy element %s deleted', $elementId);
$this->Flash->success($message);
} else {
$message = __('Could not delete galaxy element');
$this->Flash->error($message);
}
$this->redirect($this->referer());
} else {
if (!$this->request->is('ajax')) {
throw new MethodNotAllowedException(__('This function can only be reached via AJAX.'));
} else {
$this->layout = 'ajax';
$this->set('elementId', $elementId);
$this->render('ajax/delete');
}
}
}
public function flattenJson($clusterId)
{
$cluster = $this->GalaxyElement->GalaxyCluster->fetchIfAuthorized($this->Auth->user(), $clusterId, array('edit'), true, false);
if ($this->request->is('post') || $this->request->is('put')) {
$json = $this->GalaxyElement->jsonDecode($this->request->data['GalaxyElement']['jsonData']);
$flattened = Hash::flatten($json);
$newElements = [];
foreach ($flattened as $k => $v) {
$newElements[] = ['key' => $k, 'value' => $v];
}
$cluster['GalaxyCluster']['GalaxyElement'] = $newElements;
$errors = $this->GalaxyElement->GalaxyCluster->editCluster($this->Auth->user(), $cluster, [], false);
if (empty($errors)) {
return $this->RestResponse->saveSuccessResponse('GalaxyElement', 'flattenJson', $clusterId, false);
} else {
$message = implode(', ', $errors);
return $this->RestResponse->saveFailResponse('GalaxyElement', 'flattenJson', $clusterId, $message, false);
}
}
$this->set('clusterId', $clusterId);
if ($this->request->is('ajax')) {
$this->layout = 'ajax';
$this->render('ajax/flattenJson');
}
}
}

View File

@ -108,7 +108,7 @@ class LogsController extends AppController
}
// Shows a minimalistic history for the currently selected event
public function event_index($id)
public function event_index($id, $org = null)
{
$this->loadModel('Event');
$event = $this->Event->fetchEvent($this->Auth->user(), array(
@ -183,6 +183,10 @@ class LogsController extends AppController
);
}
if ($org) {
$conditions['org'] = $org;
}
$this->paginate['fields'] = array('title', 'created', 'model', 'model_id', 'action', 'change', 'org', 'email');
$this->paginate['conditions'] = $conditions;
@ -194,7 +198,7 @@ class LogsController extends AppController
'fields' => array('User.email')
));
foreach ($list as $k => $item) {
if (!in_array($item['Log']['email'], $orgEmails)) {
if (!in_array($item['Log']['email'], $orgEmails, true)) {
$list[$k]['Log']['email'] = '';
}
}
@ -367,6 +371,8 @@ class LogsController extends AppController
'EventTag',
'Feed',
'DecayingModel',
'EventGraph',
'EventReport',
'MispObject',
'Organisation',
'Post',

View File

@ -298,4 +298,13 @@ class ObjectTemplatesController extends AppController
$this->layout = 'ajax';
$this->render('ajax/getToggleField');
}
public function getRaw($uuidOrName)
{
$template = $this->ObjectTemplate->getRawFromDisk($uuidOrName);
if (empty($template)) {
throw new NotFoundException(__('Template not found'));
}
return $this->RestResponse->viewData($template, $this->response->type());
}
}

View File

@ -1042,35 +1042,35 @@ class ServersController extends AppController
$this->set('branch', $gitStatus['branch']);
$this->set('commit', $gitStatus['commit']);
$this->set('latestCommit', $gitStatus['latestCommit']);
$phpSettings = array(
'max_execution_time' => array(
'explanation' => 'The maximum duration that a script can run (does not affect the background workers). A too low number will break long running scripts like comprehensive API exports',
'recommended' => 300,
'unit' => false
'unit' => 'seconds',
),
'memory_limit' => array(
'explanation' => 'The maximum memory that PHP can consume. It is recommended to raise this number since certain exports can generate a fair bit of memory usage',
'recommended' => 2048,
'unit' => 'M'
'unit' => 'MB'
),
'upload_max_filesize' => array(
'explanation' => 'The maximum size that an uploaded file can be. It is recommended to raise this number to allow for the upload of larger samples',
'recommended' => 50,
'unit' => 'M'
'unit' => 'MB'
),
'post_max_size' => array(
'explanation' => 'The maximum size of a POSTed message, this has to be at least the same size as the upload_max_filesize setting',
'recommended' => 50,
'unit' => 'M'
'unit' => 'MB'
)
);
foreach ($phpSettings as $setting => $settingArray) {
$phpSettings[$setting]['value'] = ini_get($setting);
if ($settingArray['unit']) {
$phpSettings[$setting]['value'] = intval(rtrim($phpSettings[$setting]['value'], $phpSettings[$setting]['unit']));
} else {
$phpSettings[$setting]['value'] = intval($phpSettings[$setting]['value']);
$phpSettings[$setting]['value'] = $this->Server->getIniSetting($setting);
if ($phpSettings[$setting]['value'] && $settingArray['unit'] && $settingArray['unit'] === 'MB') {
// convert basic unit to M
$phpSettings[$setting]['value'] = (int) floor($phpSettings[$setting]['value'] / 1024 / 1024);
}
}
$this->set('phpSettings', $phpSettings);
@ -1342,17 +1342,20 @@ class ServersController extends AppController
continue;
}
$exception = null;
try {
$remote_event = $this->Event->downloadEventFromServer($local_event['Event']['uuid'], $server, null, true);
$remote_event_id = $remote_event[0]['id'];
$remoteEvent = $this->Event->downloadEventFromServer($local_event['Event']['uuid'], $server, null, true);
} catch (Exception $e) {
$remote_event_id = null;
$remoteEvent = null;
$exception = $e->getMessage();
}
$remoteEventId = isset($remoteEvent[0]['id']) ? $remoteEvent[0]['id'] : null;
$remote_events[] = array(
"server_id" => $server['Server']['id'],
"server_name" => $server['Server']['name'],
"url" => isset($remote_event_id) ? $server['Server']['url']."/events/view/".$remote_event_id : $server['Server']['url'],
"remote_id" => isset($remote_event_id) ? $remote_event_id : false
"url" => isset($remoteEventId) ? $server['Server']['url'] . "/events/view/" . $remoteEventId : $server['Server']['url'],
"remote_id" => isset($remoteEventId) ? $remoteEventId : false,
"exception" => $exception,
);
}
@ -1652,10 +1655,6 @@ class ServersController extends AppController
public function testConnection($id = false)
{
if (!$this->Auth->user('Role')['perm_sync'] && !$this->Auth->user('Role')['perm_site_admin']) {
throw new MethodNotAllowedException('You don\'t have permission to do that.');
}
$server = $this->Server->find('first', ['conditions' => ['Server.id' => $id]]);
if (!$server) {
throw new NotFoundException(__('Invalid server'));

View File

@ -828,6 +828,52 @@ class ShadowAttributesController extends AppController
$this->set('_serialize', array('ShadowAttribute'));
}
public function viewPicture($id, $thumbnail=false)
{
$conditions['ShadowAttribute.id'] = $id;
$conditions['ShadowAttribute.type'] = 'attachment';
$options = array(
'conditions' => $conditions,
'includeAllTags' => false,
'includeAttributeUuid' => true,
'flatten' => true,
'deleted' => [0, 1]
);
$sa = $this->ShadowAttribute->find('first', array(
'recursive' => -1,
'contain' => ['Event', 'Attribute'], // required because of conditions
'fields' => array(
'ShadowAttribute.id', 'ShadowAttribute.old_id', 'ShadowAttribute.event_id', 'ShadowAttribute.type', 'ShadowAttribute.category', 'ShadowAttribute.uuid', 'ShadowAttribute.to_ids', 'ShadowAttribute.value', 'ShadowAttribute.comment', 'ShadowAttribute.org_id', 'ShadowAttribute.first_seen', 'ShadowAttribute.last_seen',
),
'conditions' => $conditions,
));
if (empty($sa)) {
throw new NotFoundException(__('Invalid proposal.'));
}
if (!$this->ShadowAttribute->Attribute->isImage($sa['ShadowAttribute'])) {
throw new NotFoundException("ShadowAttribute is not an image.");
}
if ($this->_isRest()) {
if ($this->ShadowAttribute->typeIsAttachment($sa['ShadowAttribute']['type'])) {
$encodedFile = $this->ShadowAttribute->base64EncodeAttachment($sa['ShadowAttribute']);
$sa['ShadowAttribute']['data'] = $encodedFile;
}
}
if ($this->_isRest()) {
return $this->RestResponse->viewData($sa['ShadowAttribute']['data'], $this->response->type());
} else {
$width = isset($this->request->params['named']['width']) ? $this->request->params['named']['width'] : 200;
$height = isset($this->request->params['named']['height']) ? $this->request->params['named']['height'] : 200;
$imageData = $this->ShadowAttribute->getPictureData($sa, $thumbnail, $width, $height);
$extension = pathinfo($sa['ShadowAttribute']['value'], PATHINFO_EXTENSION);
return new CakeResponse(array('body' => $imageData, 'type' => strtolower($extension)));
}
}
public function index($eventId = false)
{
$conditions = array();

View File

@ -608,7 +608,7 @@ class SharingGroupsController extends AppController
}
}
}
if (false === $addServer) {
if (false === $removeServer) {
return $this->RestResponse->saveFailResponse('SharingGroup', $this->action, false, 'Server is not in the sharing group.', $this->response->type());
}
$result = $this->SharingGroup->SharingGroupServer->delete($removeServer);

View File

@ -41,7 +41,6 @@ class TagsController extends AppController
'request' => $this->request,
'named_params' => $this->params['named'],
'paramArray' => ['favouritesOnly', 'filter', 'searchall', 'name', 'search', 'exclude_statistics'],
'ordered_url_params' => @compact($paramArray)
);
$exception = false;
$passedArgsArray = $this->_harvestParameters($filterData, $exception);
@ -344,79 +343,33 @@ class TagsController extends AppController
public function view($id)
{
if ($this->_isRest()) {
$contain = array('EventTag' => array('fields' => 'event_id'));
$contain['AttributeTag'] = array('fields' => 'attribute_id');
$tag = $this->Tag->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1,
'contain' => $contain
));
if (empty($tag)) {
throw new MethodNotAllowedException('Invalid Tag');
}
if (empty($tag['EventTag'])) {
$tag['Tag']['count'] = 0;
} else {
$eventIDs = array();
foreach ($tag['EventTag'] as $eventTag) {
$eventIDs[] = $eventTag['event_id'];
}
$conditions = array('Event.id' => $eventIDs);
if (!$this->_isSiteAdmin()) {
$conditions = array_merge(
$conditions,
array('OR' => array(
array('AND' => array(
array('Event.distribution >' => 0),
array('Event.published =' => 1)
)),
array('Event.orgc_id' => $this->Auth->user('org_id'))
))
);
}
$events = $this->Tag->EventTag->Event->find('all', array(
'fields' => array('Event.id', 'Event.distribution', 'Event.orgc_id'),
'conditions' => $conditions
));
$tag['Tag']['count'] = count($events);
}
unset($tag['EventTag']);
if (empty($tag['AttributeTag'])) {
$tag['Tag']['attribute_count'] = 0;
} else {
$attributeIDs = array();
foreach ($tag['AttributeTag'] as $attributeTag) {
$attributeIDs[] = $attributeTag['attribute_id'];
}
$conditions = array('Attribute.id' => $attributeIDs);
if (!$this->_isSiteAdmin()) {
$conditions = array_merge(
$conditions,
array('OR' => array(
array('AND' => array(
array('Attribute.deleted =' => 0),
array('Attribute.distribution >' => 0),
array('Event.distribution >' => 0),
array('Event.published =' => 1)
)),
array('Event.orgc_id' => $this->Auth->user('org_id'))
))
);
}
$attributes = $this->Tag->AttributeTag->Attribute->find('all', array(
'fields' => array('Attribute.id', 'Attribute.deleted', 'Attribute.distribution', 'Event.id', 'Event.distribution', 'Event.orgc_id'),
'contain' => array('Event' => array('fields' => array('id', 'distribution', 'orgc_id'))),
'conditions' => $conditions
));
$tag['Tag']['attribute_count'] = count($attributes);
}
unset($tag['AttributeTag']);
$this->set('Tag', $tag['Tag']);
$this->set('_serialize', 'Tag');
} else {
if (!$this->_isRest()) {
throw new MethodNotAllowedException('This action is only for REST users.');
}
$tag = $this->Tag->find('first', array(
'conditions' => array('id' => $id),
'recursive' => -1,
'contain' => ['AttributeTag' => ['fields' => 'attribute_id']],
));
if (empty($tag)) {
throw new MethodNotAllowedException('Invalid Tag');
}
$tag['Tag']['count'] = $this->Tag->EventTag->countForTag($tag['Tag']['id'], $this->Auth->user());
if (empty($tag['AttributeTag'])) {
$tag['Tag']['attribute_count'] = 0;
} else {
$attributeIDs = array_column($tag['AttributeTag'], 'attribute_id');
$tag['Tag']['attribute_count'] = count($this->Tag->AttributeTag->Attribute->fetchAttributes($this->Auth->user(), [
'conditions' => ['Attribute.id' => $attributeIDs],
'list' => true,
]));
}
unset($tag['AttributeTag']);
return $this->RestResponse->viewData($tag['Tag'], $this->response->type());
}
public function showEventTag($id)

View File

@ -9,17 +9,17 @@ class TaxonomiesController extends AppController
public $components = array('Session', 'RequestHandler');
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'contain' => array(
'TaxonomyPredicate' => array(
'fields' => array('TaxonomyPredicate.id'),
'TaxonomyEntry' => array('fields' => array('TaxonomyEntry.id'))
)
),
'order' => array(
'Taxonomy.id' => 'DESC'
),
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user van view/page.
'contain' => array(
'TaxonomyPredicate' => array(
'fields' => array('TaxonomyPredicate.id', 'TaxonomyPredicate.value'),
'TaxonomyEntry' => array('fields' => array('TaxonomyEntry.id', 'TaxonomyEntry.value'))
)
),
'order' => array(
'Taxonomy.id' => 'DESC'
),
);
public function index()
@ -46,25 +46,15 @@ class TaxonomiesController extends AppController
} else {
$taxonomies = $this->paginate();
}
$this->loadModel('Tag');
foreach ($taxonomies as $key => $taxonomy) {
$total = 0;
foreach ($taxonomy['TaxonomyPredicate'] as $predicate) {
$total += empty($predicate['TaxonomyEntry']) ? 1 : count($predicate['TaxonomyEntry']);
}
$taxonomies[$key]['total_count'] = $total;
$taxonomies[$key]['current_count'] = $this->Tag->find('count', array(
'conditions' => array('lower(Tag.name) LIKE ' => strtolower($taxonomy['Taxonomy']['namespace']) . ':%', 'hide_tag' => 0),
'recursive' => -1,
));
unset($taxonomies[$key]['TaxonomyPredicate']);
}
$taxonomies = $this->__tagCount($taxonomies);
if ($this->_isRest()) {
return $this->RestResponse->viewData($taxonomies, $this->response->type());
} else {
$this->set('taxonomies', $taxonomies);
$this->set('passedArgsArray', $this->passedArgs);
}
$this->set('taxonomies', $taxonomies);
$this->set('passedArgsArray', $this->passedArgs);
}
public function view($id)
@ -469,6 +459,53 @@ class TaxonomiesController extends AppController
$this->render('ajax/toggle_required');
}
/**
* Attach tag counts.
* @param array $taxonomies
* @return array
*/
private function __tagCount(array $taxonomies)
{
$tags = [];
foreach ($taxonomies as $taxonomyPos => $taxonomy) {
$total = 0;
foreach ($taxonomy['TaxonomyPredicate'] as $predicate) {
if (isset($predicate['TaxonomyEntry']) && !empty($predicate['TaxonomyEntry'])) {
foreach ($predicate['TaxonomyEntry'] as $entry) {
$tag = mb_strtolower($taxonomy['Taxonomy']['namespace'] . ':' . $predicate['value'] . '="' . $entry['value'] . '"');
$tags[$tag] = $taxonomyPos;
$total++;
}
} else {
$tag = mb_strtolower($taxonomy['Taxonomy']['namespace'] . ':' . $predicate['value']);
$tags[$tag] = $taxonomyPos;
$total++;
}
}
$taxonomies[$taxonomyPos]['total_count'] = $total;
$taxonomies[$taxonomyPos]['current_count'] = 0;
unset($taxonomies[$taxonomyPos]['TaxonomyPredicate']);
}
$this->loadModel('Tag');
$existingTags = $this->Tag->find('column', [
'fields' => ['Tag.name'],
'conditions' => [
'lower(Tag.name)' => array_keys($tags),
'hide_tag' => 0
],
]);
foreach ($existingTags as $existingTag) {
$existingTag = mb_strtolower($existingTag);
if (isset($tags[$existingTag])) {
$taxonomies[$tags[$existingTag]]['current_count']++;
}
}
return $taxonomies;
}
private function __search($value)
{
$value = mb_strtolower(trim($value));

View File

@ -9,20 +9,20 @@ class WarninglistsController extends AppController
public $components = array('Session', 'RequestHandler');
public $paginate = array(
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user can view/page.
'contain' => array(
'WarninglistType'
),
'order' => array(
'Warninglist.id' => 'DESC'
),
'limit' => 60,
'maxLimit' => 9999, // LATER we will bump here on a problem once we have more than 9999 events <- no we won't, this is the max a user can view/page.
'contain' => array(
'WarninglistType'
),
'order' => array(
'Warninglist.id' => 'DESC'
),
'recursive' => -1,
);
public function index()
{
$filters = $this->IndexFilter->harvestParameters(['value']);
$this->paginate['recursive'] = -1;
$filters = $this->IndexFilter->harvestParameters(['value', 'enabled']);
if (!empty($filters['value'])) {
$this->paginate['conditions'] = [
'OR' => [
@ -32,20 +32,20 @@ class WarninglistsController extends AppController
]
];
}
if (isset($filters['enabled'])) {
$this->paginate['conditions'][] = ['Warninglist.enabled' => $filters['enabled']];
}
$warninglists = $this->paginate();
foreach ($warninglists as &$warninglist) {
$warninglist['Warninglist']['valid_attributes'] = array();
foreach ($warninglist['WarninglistType'] as $type) {
$warninglist['Warninglist']['valid_attributes'][] = $type['type'];
}
$warninglist['Warninglist']['valid_attributes'] = implode(', ', $warninglist['Warninglist']['valid_attributes']);
$validAttributes = array_column($warninglist['WarninglistType'], 'type');
$warninglist['Warninglist']['valid_attributes'] = implode(', ', $validAttributes);
unset($warninglist['WarninglistType']);
}
if ($this->_isRest()) {
$this->set('Warninglists', $warninglists);
$this->set('_serialize', array('Warninglists'));
return $this->RestResponse->viewData(['Warninglists' => $warninglists], $this->response->type());
} else {
$this->set('warninglists', $warninglists);
$this->set('passedArgsArray', $filters);
}
}

View File

@ -55,7 +55,7 @@ class CsseCovidTrendsWidget
'date' => (empty($options['timeframe']) ? 10 : $options['timeframe']) . 'd'
);
$eventIds = $this->Event->filterEventIds($user, $params);
$eventIds = array_reverse(array_values($eventIds));
$eventIds = array_reverse($eventIds);
$data = array();
if (empty($options['type'])) {
$options['type'] = 'confirmed';

View File

@ -0,0 +1,88 @@
<?php
class EventStreamWidget
{
public $title = 'Event Stream';
public $render = 'Index';
public $width = 4;
public $height = 2;
public $params = [
'tags' => 'A list of tagnames to filter on. Comma separated list, prepend each tag with an exclamation mark to negate it.',
'orgs' => 'A list of organisation names to filter on. Comma separated list, prepend each tag with an exclamation mark to negate it.',
'published' => 'Boolean flag to filter on published events only',
'limit' => 'How many events should be listed? Defaults to 5',
'fields' => 'A list of fields that should be displayed. Valid fields: id, orgc, info, tags, threat_level, analysis, date. Default field selection ["id", "orgc", "info"]'
];
public $description = 'Monitor incoming events based on your own filters.';
public $cacheLifetime = false;
public $autoRefreshDelay = 5;
private $__default_fields = ['id', 'orgc', 'info'];
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
$params = [
'metadata' => 1,
'limit' => 5,
'page' => 1,
'order' => 'Event.id DESC'
];
$field_options = [
'id' => [
'name' => '#',
'url' => Configure::read('MISP.baseurl') . '/events/view',
'element' => 'links',
'data_path' => 'Event.id',
'url_params_data_paths' => 'Event.id'
],
'orgc' => [
'name' => 'Org',
'data_path' => 'Orgc',
'element' => 'org'
],
'info' => [
'name' => 'Info',
'data_path' => 'Event.info',
],
'tags' => [
'name' => 'Tags',
'data_path' => 'EventTag',
'element' => 'tags',
'scope' => 'feeds'
],
'threat_level' => [
'name' => 'Threat Level',
'data_path' => 'ThreatLevel.name'
],
'analysis' => [
'name' => 'Analysis',
'data_path' => 'Event.analysis',
'element' => 'array_lookup_field',
'arrayData' => [__('Initial'), __('Ongoing'), __('Complete')]
],
'date' => [
'name' => 'Date',
'data_path' => 'Event.date'
],
];
$fields = [];
if (empty($options['fields'])) {
$options['fields'] = $this->__default_fields;
}
foreach ($options['fields'] as $field) {
if (!empty($field_options[$field])) {
$fields[] = $field_options[$field];
}
}
foreach (['published', 'limit', 'tags', 'orgs'] as $field) {
if (!empty($options[$field])) {
$params[$field] = $options[$field];
}
}
$data = $this->Event->fetchEvent($user, $params);
return [
'data' => $data,
'fields' => $fields
];
}
}

View File

@ -7,41 +7,43 @@ class MispSystemResourceWidget
public $width = 3;
public $height = 3;
public $params = array(
'treshold' => 'Treshold for disk space'
'threshold' => 'Threshold for disk space'
);
public $description = 'Basic widget showing some system server statistics.';
public $cacheLifetime = false;
public $autoRefreshDelay = 30;
public $placeholder =
'{
"treshold": "85"
"threshold": "85"
}';
public function handler($user, $options = array())
public function handler(array $user, $options = array())
{
// Keep BC with typo value
$threshold = isset($options['threshold']) ? $options['threshold'] : (isset($options['treshold']) ? $options['treshold'] : 85);
$drive = round((1 - disk_free_space(getcwd())/disk_total_space(getcwd()))*100,2);
$cwd = getcwd();
$drive = round((1 - disk_free_space($cwd)/disk_total_space($cwd))*100,2);
$driveFree = $drive . "%";
$driveFreeClass = "";
if ($drive > intval($options['treshold'])) {
$driveFree = $drive . "% - [Above Treshhold]";
if ($drive > intval($threshold)) {
$driveFree = $drive . "% - [Above Threshold]";
$driveFreeClass = "red";
}
$sysload = sys_getloadavg();
preg_match('#MemFree:[\s\t]+([\d]+)\s+kB#', file_get_contents('/proc/meminfo'), $matches);
$meminfo = file_get_contents('/proc/meminfo');
preg_match('#MemFree:[\s\t]+([\d]+)\s+kB#', $meminfo, $matches);
$memoryFree = $matches[1];
preg_match('#MemTotal:[\s\t]+([\d]+)\s+kB#', file_get_contents('/proc/meminfo'), $matches);
preg_match('#MemTotal:[\s\t]+([\d]+)\s+kB#', $meminfo, $matches);
$memoryTotal = $matches[1];
$data = array(
array( 'title' => __('User'), 'value' => $user['email']),
array( 'title' => __('System'), 'value' => php_uname()),
array( 'title' => __('Disk usage'), 'value' => h($driveFree), 'class' => $driveFreeClass),
array( 'title' => __('Load'), 'value' => h($sysload[0] . " - " . $sysload[1] . " - " . $sysload[2])),
array( 'title' => __('Memory'), 'value' => h(round($memoryFree/1024,2) . "M free (" . round((1 - $memoryFree/$memoryTotal)*100,2) . "% used)")),
);
array( 'title' => __('User'), 'value' => $user['email']),
array( 'title' => __('System'), 'value' => php_uname()),
array( 'title' => __('Disk usage'), 'value' => h($driveFree), 'class' => $driveFreeClass),
array( 'title' => __('Load'), 'value' => h(implode(" - ", sys_getloadavg()))),
array( 'title' => __('Memory'), 'value' => h(round($memoryFree / 1024,2) . " MB free (" . round((1 - $memoryFree/$memoryTotal)*100,2) . " % used)")),
);
return $data;
}

View File

@ -20,36 +20,41 @@ class TrendingTagsWidget
"include": ["misp-galaxy:", "my-internal-taxonomy"]
}';
public $description = 'Widget showing the trending tags over the past x seconds, along with the possibility to include/exclude tags.';
public $cacheLifetime = 600;
public function handler($user, $options = array())
{
$this->Event = ClassRegistry::init('Event');
$params = array(
'metadata' => 1,
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window'])
);
/** @var Event $eventModel */
$eventModel = ClassRegistry::init('Event');
$threshold = empty($options['threshold']) ? 10 : $options['threshold'];
$eventIds = $this->Event->filterEventIds($user, $params);
$params['eventid'] = $eventIds;
$events = array();
$params = [
'timestamp' => time() - (empty($options['time_window']) ? 8640000 : $options['time_window']),
];
$eventIds = $eventModel->filterEventIds($user, $params);
$tags = [];
$tagColours = [];
if (!empty($eventIds)) {
$events = $this->Event->fetchEvent($user, $params);
}
$tags = array();
$tagColours = array();
foreach ($events as $event) {
foreach ($event['EventTag'] as $et) {
if ($this->checkTag($options, $et['Tag']['name'])) {
if (empty($tags[$et['Tag']['name']])) {
$tags[$et['Tag']['name']] = 1;
$tagColours[$et['Tag']['name']] = $et['Tag']['colour'];
} else {
$tags[$et['Tag']['name']] += 1;
}
$eventTags = $eventModel->EventTag->find('all', [
'conditions' => ['EventTag.event_id' => $eventIds],
'contain' => ['Tag' => ['fields' => ['name', 'colour']]],
'recursive' => -1,
'fields' => ['id'],
]);
foreach ($eventTags as $eventTag) {
$tagName = $eventTag['Tag']['name'];
if (isset($tags[$tagName])) {
$tags[$tagName]++;
} else if ($this->checkTag($options, $tagName)) {
$tags[$tagName] = 1;
$tagColours[$tagName] = $eventTag['Tag']['colour'];
}
}
arsort($tags);
}
arsort($tags);
$data['data'] = array_slice($tags, 0, $threshold);
$data['colours'] = $tagColours;
return $data;

View File

@ -6,6 +6,7 @@ class CsvExport
public $default_fields = array('uuid', 'event_id', 'category', 'type', 'value', 'comment', 'to_ids', 'timestamp', 'object_relation', 'attribute_tag');
public $default_obj_fields = array('object_uuid', 'object_name', 'object_meta-category');
public $requested_fields = array();
public $decaying_fields = array('decay_score_score', 'decay_score_decayed');
public $non_restrictive_export = true;
public function handler($data, $options = array())
@ -22,6 +23,9 @@ class CsvExport
public function modify_params($user, $params)
{
if (!empty($params['includeDecayScore'])) {
$this->enable_decaying();
}
if (empty($params['contain'])) {
$params['contain'] = array();
}
@ -36,6 +40,11 @@ class CsvExport
return $params;
}
public function enable_decaying()
{
$this->default_fields = array_merge($this->default_fields, $this->decaying_fields);
}
private function __attributesHandler($attribute, $options)
{
$attribute = $this->__addMetadataToAttributeAtomic($attribute);
@ -44,6 +53,17 @@ class CsvExport
$attribute['object_name'] = $attribute['Object']['name'];
$attribute['object_meta-category'] = $attribute['Object']['meta-category'];
}
if (!empty($attribute['decay_score'])) {
$all_scores = Hash::extract($attribute, 'decay_score.{n}.score');
$all_decayed = Hash::extract($attribute, 'decay_score.{n}.decayed');
$avg_score = array_sum($all_scores)/count($all_scores);
$avg_decayed = count(array_intersect([true], $all_decayed)) > 0;
$attribute['decay_score_score'] = $avg_score;
$attribute['decay_score_decayed'] = $avg_decayed;
} else {
$attribute['decay_score_score'] = 0;
$attribute['decay_score_decayed'] = false;
}
return $this->__addLine($attribute, $options);
}

125
app/Lib/Tools/CidrTool.php Normal file
View File

@ -0,0 +1,125 @@
<?php
class CidrTool
{
/** @var array */
private $ipv4 = [];
/**
* Minimum netmask for IPv4 in list. 33 because maximum netmask is 32..
* @var int
*/
private $minimumIpv4Mask = 33;
/** @var array */
private $ipv6 = [];
public function __construct(array $list)
{
$this->filterInputList($list);
}
/**
* @param string $value IPv4 or IPv6 address or range
* @return false|string
*/
public function contains($value)
{
$valueMask = null;
if (strpos($value, '/') !== false) {
list($value, $valueMask) = explode('/', $value);
}
$match = false;
if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
// This code converts IP address to all possible CIDRs that can contains given IP address
// and then check if given hash table contains that CIDR.
$ip = ip2long($value);
// Start from 1, because doesn't make sense to check 0.0.0.0/0 match
for ($bits = $this->minimumIpv4Mask; $bits <= 32; $bits++) {
$mask = -1 << (32 - $bits);
$needle = long2ip($ip & $mask) . "/$bits";
if (isset($this->ipv4[$needle])) {
$match = $needle;
break;
}
}
} elseif (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$value = unpack('n*', inet_pton($value));
foreach ($this->ipv6 as $netmask => $lv) {
foreach ($lv as $l) {
if ($this->ipv6InCidr($value, $l, $netmask)) {
$match = inet_ntop($l) . "/$netmask";
break;
}
}
}
}
if ($match && $valueMask) {
$matchMask = explode('/', $match)[1];
if ($valueMask < $matchMask) {
return false;
}
}
return $match;
}
/**
* Using solution from https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/IpUtils.php
*
* @param array $ip
* @param string $cidr
* @param int $netmask
* @return bool
*/
private function ipv6InCidr($ip, $cidr, $netmask)
{
$bytesAddr = unpack('n*', $cidr);
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
$left = $netmask - 16 * ($i - 1);
$left = ($left <= 16) ? $left : 16;
$mask = ~(0xffff >> $left) & 0xffff;
if (($bytesAddr[$i] & $mask) != ($ip[$i] & $mask)) {
return false;
}
}
return true;
}
/**
* Filter out invalid IPv4 or IPv4 CIDR and append maximum netmask if no netmask is given.
* @param array $list
*/
private function filterInputList(array $list)
{
foreach ($list as $v) {
$parts = explode('/', $v, 2);
$ipBytes = inet_pton($parts[0]);
if ($ipBytes === false) {
continue; // IP address part of CIDR is invalid
}
$maximumNetmask = strlen($ipBytes) === 4 ? 32 : 128;
if (isset($parts[1]) && ($parts[1] > $maximumNetmask || $parts[1] < 0)) {
// Netmask part of CIDR is invalid
continue;
}
$mask = isset($parts[1]) ? $parts[1] : $maximumNetmask;
if ($maximumNetmask === 32) {
if ($mask < $this->minimumIpv4Mask) {
$this->minimumIpv4Mask = (int)$mask;
}
if (!isset($parts[1])) {
$v = "$v/$maximumNetmask"; // If CIDR doesnt contains '/', we will consider CIDR as /32
}
$this->ipv4[$v] = true;
} else {
$this->ipv6[$mask][] = $ipBytes;
}
}
}
}

View File

@ -4,13 +4,14 @@
private $__lookupTables = array();
private $__related_events = array();
private $__related_attributes = array();
private $__eventModel = false;
/** @var Event */
private $__eventModel;
private $__taxonomyModel = false;
private $__galaxyClusterModel = false;
private $__user = false;
private $__json = array();
public function construct($eventModel, $taxonomyModel, $galaxyClusterModel, $user, $json)
public function construct(Event $eventModel, $taxonomyModel, $galaxyClusterModel, $user, $json)
{
$this->__eventModel = $eventModel;
$this->__taxonomyModel = $taxonomyModel;
@ -99,11 +100,11 @@
{
foreach ($objects as $k => $object) {
$include = $full;
if (!$include) {
if (!$include && isset($object['Attribute'])) {
foreach ($object['Attribute'] as $attribute) {
if (isset($this->__related_attributes[$attribute['id']])) {
$include = true;
continue;
break;
}
}
}

View File

@ -40,6 +40,9 @@ class ElasticSearchClient
// Format timestamp
$time = strftime("%Y-%m-%d %H:%M:%S", strtotime($document["Log"]["created"]));
$document["Log"]["created"] = $time;
if (empty($document["Log"]["ip"])) {
$document["Log"]["ip"] = null;
}
$params = array(
'index' => $index,
'type' => $document_type,

View File

@ -77,6 +77,11 @@
if (!($check1 && $check2)) {
unset($event['Object'][$i]);
}
foreach($obj['ObjectReference'] as $j => $rel) {
if ($rel['deleted']) {
unset($event['Object'][$i]['ObjectReference'][$j]);
}
}
}
foreach ($event['Attribute'] as $i => $attr) {
$check1 = $this->__satisfy_val_filtering($attr, false);
@ -519,7 +524,7 @@
public function get_reference_data($uuid)
{
$objectReference = $this->__refModel->ObjectReference->find('all', array(
'conditions' => array('ObjectReference.uuid' => $uuid),
'conditions' => array('ObjectReference.uuid' => $uuid, 'ObjectReference.deleted' => false),
'recursive' => -1,
//'fields' => array('ObjectReference.id', 'relationship_type', 'comment', 'referenced_uuid')
));

View File

@ -107,7 +107,7 @@ class HttpSocketExtended extends HttpSocket
}
// Convert connection timeout to SocketException
if (!empty($this->lastError)) {
throw new SocketException($this->lastError['msg']);
throw new SocketException($this->lastError['str']);
}
return $response;
}

View File

@ -105,18 +105,19 @@ class JSONConverterTool
}
/**
* Event to JSON stream convertor.
* Event to JSON convertor, but that is intended for machine to machine communication
* @param array $event
* @return Generator<string>
*/
public function streamConvert(array $event)
{
$event = $this->convert($event, false, true);
// Fast and inaccurate way how to check if event is too big for to convert in one call. This can be changed in future.
$isBigEvent = (isset($event['Event']['Attribute']) ? count($event['Event']['Attribute']) : 0) +
(isset($event['Event']['Object']) ? count($event['Event']['Object']) : 0) > 100;
if (!$isBigEvent) {
yield json_encode($event, JSON_PRETTY_PRINT);
yield json_encode($event, JSON_UNESCAPED_UNICODE);
return;
}
@ -127,11 +128,11 @@ class JSONConverterTool
yield ($firstKey === $key ? '' : ',') . json_encode($key) . ":[";
$firstInnerKey = key($value);
foreach ($value as $i => $attribute) {
yield ($firstInnerKey === $i ? '' : ',') . json_encode($attribute);
yield ($firstInnerKey === $i ? '' : ',') . json_encode($attribute, JSON_UNESCAPED_UNICODE);
}
yield "]";
} else {
yield ($firstKey === $key ? '' : ',') . json_encode($key) . ":" . json_encode($value);
yield ($firstKey === $key ? '' : ',') . json_encode($key) . ":" . json_encode($value, JSON_UNESCAPED_UNICODE);
}
}
if (isset($event['errors'])) {

View File

@ -729,14 +729,14 @@ class SendEmail
}
list($inputFile, $outputFile) = $this->createInputOutputFiles($body);
$result = openssl_pkcs7_sign($inputFile->pwd(), $outputFile->pwd(), $certPublicSign, $keySign, array(), 0);
$result = openssl_pkcs7_sign($inputFile->pwd(), $outputFile->pwd(), $certPublicSign, $keySign, array(), PKCS7_DETACHED);
$inputFile->delete();
if ($result) {
$data = $outputFile->read();
$outputFile->delete();
$parts = explode("\n\n", $data);
return $parts[1] . "\n";
return $parts[4] . "\n";
} else {
$outputFile->delete();

View File

@ -14,7 +14,7 @@ class TmpFileTool
public function __construct($maxInMemory = null)
{
if ($maxInMemory === null) {
$maxInMemory = 2 * 1024 * 1024;
$maxInMemory = 5 * 1024 * 1024;
}
$this->tmpfile = fopen("php://temp/maxmemory:$maxInMemory", "w+");
if ($this->tmpfile === false) {

View File

@ -198,13 +198,18 @@ class XMLConverterTool
$field = str_replace($this->__toEscape, $this->__escapeWith, $field);
}
/**
* @param string $input
* @param false $mispVersion
* @return Generator
*/
public function frameCollection($input, $mispVersion = false)
{
$result = '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . '<response>' . PHP_EOL;
$result .= $input;
yield '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . '<response>' . PHP_EOL;
yield $input . PHP_EOL;
if ($mispVersion) {
$result .= '<xml_version>' . $mispVersion . '</xml_version>';
yield '<xml_version>' . $mispVersion . '</xml_version>';
}
return $result . '</response>' . PHP_EOL;
yield '</response>' . PHP_EOL;
}
}

@ -1 +1 @@
Subproject commit d0c51b37422d0d2c99be74045d4439a674259308
Subproject commit cf14e6546ec44e3369e3531add11fdb946656280

View File

@ -4100,11 +4100,11 @@ msgid "Click this to download all network related attributes that you have acces
msgstr ""
#: Model/Event.php:446
msgid "Click this to download an a STIX document containing the STIX version of all events and attributes that you have access to."
msgid "Click this to download a STIX document containing the STIX version of all events and attributes that you have access to."
msgstr ""
#: Model/Event.php:454
msgid "Click this to download an a STIX2 document containing the STIX2 version of all events and attributes that you have access to."
msgid "Click this to download a STIX2 document containing the STIX2 version of all events and attributes that you have access to."
msgstr ""
#: Model/Event.php:462

View File

@ -12,6 +12,7 @@ App::uses('ComplexTypeTool', 'Tools');
/**
* @property Event $Event
* @property AttributeTag $AttributeTag
* @property Sighting $Sighting
* @property-read array $typeDefinitions
* @property-read array $categoryDefinitions
*/
@ -62,6 +63,7 @@ class Attribute extends AppModel
public $shortDist = array(0 => 'Organisation', 1 => 'Community', 2 => 'Connected', 3 => 'All', 4 => ' Sharing Group', 5 => 'Inherit');
private $exclusions = null;
public function __construct($id = false, $table = null, $ds = null)
{
@ -202,17 +204,17 @@ class Attribute extends AppModel
'stringNotEmpty' => array(
'rule' => array('stringNotEmpty')
),
'validComposite' => array(
'rule' => array('validComposite'),
'message' => 'Composite type found but the value not in the composite (value1|value2) format.'
),
'userdefined' => array(
'rule' => array('validateAttributeValue'),
'message' => 'Value not in the right type/format. Please double check the value or select type "other".'
),
'uniqueValue' => array(
'rule' => array('valueIsUnique'),
'message' => 'A similar attribute already exists for this event.'
),
'validComposite' => array(
'rule' => array('validComposite'),
'message' => 'Composite type found but the value not in the composite (value1|value2) format.'
'rule' => array('valueIsUnique'),
'message' => 'A similar attribute already exists for this event.'
),
'maxTextLength' => array(
'rule' => array('maxTextLength')
@ -602,7 +604,7 @@ class Attribute extends AppModel
public function validComposite($fields)
{
$compositeTypes = $this->getCompositeTypes();
if (in_array($this->data['Attribute']['type'], $compositeTypes)) {
if (in_array($this->data['Attribute']['type'], $compositeTypes, true)) {
if (substr_count($fields['value'], '|') !== 1) {
return false;
}
@ -1575,7 +1577,7 @@ class Attribute extends AppModel
* @return string
* @throws Exception
*/
private function resizeImage($data, $maxWidth, $maxHeight)
public function resizeImage($data, $maxWidth, $maxHeight)
{
$image = imagecreatefromstring($data);
if ($image === false) {
@ -1764,15 +1766,12 @@ class Attribute extends AppModel
if (!empty($a['value2'])) {
$value .= '|' . $a['value2'];
}
if (empty($this->exclusions)) {
if ($this->exclusions === null) {
try {
$redis = $this->setupRedisWithException();
} catch (Exception $e) {
$redisFail = true;
}
if (empty($redisFail)) {
$this->Correlation = ClassRegistry::init('Correlation');
$this->exclusions = $redis->sMembers('misp:correlation_exclusions');
} catch (Exception $e) {
$this->exclusions = [];
}
}
foreach ($this->exclusions as $exclusion) {
@ -1809,11 +1808,11 @@ class Attribute extends AppModel
if (!empty($a['disable_correlation']) || Configure::read('MISP.completely_disable_correlation')) {
return true;
}
if ($this->__preventExcludedCorrelations($a)) {
// Don't do any correlation if the type is a non correlating type
if (in_array($a['type'], $this->nonCorrelatingTypes, true)) {
return true;
}
// Don't do any correlation if the type is a non correlating type
if (in_array($a['type'], $this->nonCorrelatingTypes)) {
if ($this->__preventExcludedCorrelations($a)) {
return true;
}
if (!$event) {
@ -2542,7 +2541,6 @@ class Attribute extends AppModel
'recursive' => -1, // int
'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,
'flatten' => 1
)
@ -2944,9 +2942,7 @@ class Attribute extends AppModel
if (!empty($attribute)) {
if (!empty($attribute['AttributeTag'])) {
foreach ($attribute['AttributeTag'] as $at) {
if ($at['Tag']['exportable']) {
$attribute['Attribute']['Tag'][] = $at['Tag'];
}
$attribute['Attribute']['Tag'][] = $at['Tag'];
}
}
unset($attribute['AttributeTag']);
@ -3092,7 +3088,7 @@ class Attribute extends AppModel
$params['conditions']['AND'][] = $options['conditions'];
}
if (empty($options['flatten'])) {
$params['conditions']['AND'][] = array('(Attribute.object_id + 0)' => 0);
$params['conditions']['AND'][] = array('Attribute.object_id' => 0);
}
if (isset($options['order'])) {
$params['order'] = $options['order'];
@ -3127,7 +3123,7 @@ class Attribute extends AppModel
$options['includeEventTags'] = true;
}
if (!$user['Role']['perm_sync'] || !isset($options['deleted']) || !$options['deleted']) {
$params['conditions']['AND']['(Attribute.deleted + 0)'] = 0;
$params['conditions']['AND']['Attribute.deleted'] = 0;
} else {
if ($options['deleted'] === "only") {
$options['deleted'] = 1;
@ -3979,7 +3975,7 @@ class Attribute extends AppModel
}
}
if (!empty($attribute['Sighting'])) {
$this->Sighting->captureSighting($attribute['Sighting'], $this->id, $eventId, $user);
$this->Sighting->captureSightings($attribute['Sighting'], $this->id, $eventId, $user);
}
}
if (!empty($this->validationErrors)) {

View File

@ -3,6 +3,7 @@ App::uses('AppModel', 'Model');
/**
* @property Tag $Tag
* @property Attribute $Attribute
*/
class AttributeTag extends AppModel
{

View File

@ -34,9 +34,8 @@ class CorrelationExclusion extends AppModel
return false;
}
$redis->del($this->key);
$exclusions = $this->find('list', [
'recursive' => -1,
'fields' => ['id', 'value']
$exclusions = $this->find('column', [
'fields' => ['value']
]);
$redis->sAddArray($this->key, $exclusions);
}
@ -85,6 +84,7 @@ class CorrelationExclusion extends AppModel
$this->Job = ClassRegistry::init('Job');
$this->Job->id = $jobId;
}
$total = count($exclusions);
foreach ($exclusions as $exclusion_chunk) {
$i = 0;
foreach ($exclusion_chunk as $exclusion) {

View File

@ -340,7 +340,7 @@ class Event extends AppModel
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix', 'includeAttachments' => 1),
'description' => __('Click this to download an a STIX document containing the STIX version of all events and attributes that you have access to.')
'description' => __('Click this to download a STIX document containing the STIX version of all events and attributes that you have access to.')
),
'stix2' => array(
'extension' => '.json',
@ -348,7 +348,7 @@ class Event extends AppModel
'scope' => 'Event',
'requiresPublished' => 1,
'params' => array('returnFormat' => 'stix2', 'includeAttachments' => 1),
'description' => __('Click this to download an a STIX2 document containing the STIX2 version of all events and attributes that you have access to.')
'description' => __('Click this to download a STIX2 document containing the STIX2 version of all events and attributes that you have access to.')
),
'rpz' => array(
'extension' => '.txt',
@ -1325,7 +1325,7 @@ class Event extends AppModel
if (!$eventReportSupportedByRemote) {
return [];
}
// Downgrade the object from connected communities to community only
if (!$server['Server']['internal'] && $report['distribution'] == 2) {
$report['distribution'] = 1;
@ -1571,6 +1571,12 @@ class Event extends AppModel
return $tempConditions;
}
/**
* @param array $user
* @param array $params
* @param int $result_count
* @return array Event IDs, when `include_attribute_count` is enabled, then it is Event ID => Attribute count
*/
public function filterEventIds($user, &$params = array(), &$result_count = 0)
{
$conditions = $this->createEventConditions($user);
@ -1654,14 +1660,9 @@ class Event extends AppModel
}
}
}
$fields = array('Event.id');
if (!empty($params['include_attribute_count'])) {
$fields[] = 'Event.attribute_count';
}
$find_params = array(
'conditions' => $conditions,
'recursive' => -1,
'fields' => $fields
);
if (isset($params['order'])) {
$find_params['order'] = $params['order'];
@ -1674,7 +1675,13 @@ class Event extends AppModel
$find_params['page'] = $params['page'];
}
}
$results = $this->find('list', $find_params);
if (!empty($params['include_attribute_count'])) {
$find_params['fields'] = array('Event.id', 'Event.attribute_count');
$results = $this->find('list', $find_params);
} else {
$find_params['fields'] = array('Event.id');
$results = $this->find('column', $find_params);
}
if (!isset($params['limit'])) {
$result_count = count($results);
}
@ -1845,7 +1852,10 @@ class Event extends AppModel
'includeServerCorrelations',
'includeWarninglistHits',
'noEventReports', // do not include event report in event data
'noShadowAttributes', // do not fetch proposals
'noShadowAttributes', // do not fetch proposals,
'limit',
'page',
'order'
);
if (!isset($options['excludeLocalTags']) && !empty($user['Role']['perm_sync']) && empty($user['Role']['perm_site_admin'])) {
$options['excludeLocalTags'] = 1;
@ -2130,6 +2140,15 @@ class Event extends AppModel
unset($params['contain']['Object']);
unset($params['contain']['EventReport']);
}
if (!empty($options['limit'])) {
$params['limit'] = $options['limit'];
}
if (!empty($options['page'])) {
$params['page'] = $options['page'];
}
if (!empty($options['order'])) {
$params['order'] = $options['order'];
}
$results = $this->find('all', $params);
if (empty($results)) {
return array();
@ -3085,16 +3104,18 @@ class Event extends AppModel
$userCount = count($usersWithAccess);
$this->UserSetting = ClassRegistry::init('UserSetting');
foreach ($usersWithAccess as $k => $user) {
if ($this->UserSetting->checkPublishFilter($user, $event)) {
// Fetch event for user that will receive alert e-mail to respect all ACLs
$eventForUser = $this->fetchEvent($user, [
'eventid' => $id,
'includeAllTags' => true,
'includeEventCorrelations' => true,
])[0];
// Fetch event for user that will receive alert e-mail to respect all ACLs
$eventForUser = $this->fetchEvent($user, [
'eventid' => $id,
'includeAllTags' => true,
'includeEventCorrelations' => true,
'noEventReports' => true,
'noSightings' => true,
])[0];
if ($this->UserSetting->checkPublishFilter($user, $eventForUser)) {
$body = $this->__buildAlertEmailBody($eventForUser, $user, $oldpublish);
$this->User->sendEmail(array('User' => $user), $body, $bodyNoEnc, $subject);
$this->User->sendEmail(['User' => $user], $body, $bodyNoEnc, $subject);
}
if ($jobId) {
$this->Job->saveProgress($jobId, null, $k / $userCount * 100);
@ -3631,6 +3652,7 @@ class Event extends AppModel
if (!$this->checkEventBlockRules($data)) {
return 'Blocked by event block rules';
}
$breakOnDuplicate = !empty($data['Event']['breakOnDuplicate']);
$this->Log = ClassRegistry::init('Log');
if (empty($data['Event']['Attribute']) && empty($data['Event']['Object']) && !empty($data['Event']['published']) && empty($data['Event']['EventReport'])) {
$this->Log->create();
@ -3853,8 +3875,9 @@ class Event extends AppModel
}
$referencesToCapture = array();
if (!empty($data['Event']['Object'])) {
foreach ($data['Event']['Object'] as $object) {
$result = $this->Object->captureObject($object, $this->id, $user, $this->Log, false);
$objectDuplicateCache = [];
foreach ($data['Event']['Object'] as $k => $object) {
$result = $this->Object->captureObject($object, $this->id, $user, $this->Log, false, $breakOnDuplicate);
}
foreach ($data['Event']['Object'] as $object) {
if (isset($object['ObjectReference'])) {
@ -5583,6 +5606,9 @@ class Event extends AppModel
}
$event['Object'] = $objects;
}
if (!empty($result['results']['EventReport'])) {
$event['EventReport'] = $result['results']['EventReport'];
}
foreach (array('Tag', 'Galaxy') as $field) {
if (!empty($result['results'][$field])) {
$event[$field] = $result['results'][$field];
@ -5620,30 +5646,38 @@ class Event extends AppModel
return $attribute;
}
public function export($user = false, $module = false, $options = array())
/**
* @param array $user
* @param string $module
* @param array $options
* @return array
* @throws Exception
*/
public function export(array $user, $module, array $options = array())
{
if (empty($user)) {
return 'Invalid user.';
}
if (empty($module)) {
return 'Invalid module.';
throw new InvalidArgumentException('Invalid module.');
}
$this->Module = ClassRegistry::init('Module');
$module = $this->Module->getEnabledModule($module, 'Export');
if (!is_array($module)) {
throw new NotFoundException('Invalid module.');
}
// Export module can specify additional options for event fetch
if (isset($module['meta']['fetch_options'])) {
$options = array_merge($options, $module['meta']['fetch_options']);
}
$events = $this->fetchEvent($user, $options);
if (empty($events)) {
return 'Invalid event.';
throw new NotFoundException('Invalid event.');
}
$standard_format = false;
$modulePayload = array('module' => $module['name']);
if (!empty($module['meta']['require_standard_format'])) {
$standard_format = true;
}
if (isset($module['meta']['config'])) {
foreach ($module['meta']['config'] as $conf) {
$modulePayload['config'][$conf] = Configure::read('Plugin.Export_' . $module['name'] . '_' . $conf);
}
}
$standard_format = !empty($module['meta']['require_standard_format']);
if ($standard_format) {
App::uses('JSONConverterTool', 'Tools');
$converter = new JSONConverterTool();
@ -5653,11 +5687,11 @@ class Event extends AppModel
}
$modulePayload['data'] = $events;
$result = $this->Module->queryModuleServer($modulePayload, false, 'Export');
return array(
'data' => $result['data'],
'extension' => $module['mispattributes']['outputFileExtension'],
'response' => $module['mispattributes']['responseType']
);
return [
'data' => $result['data'],
'extension' => $module['mispattributes']['outputFileExtension'],
'response' => $module['mispattributes']['responseType']
];
}
public function cacheSgids($user, $useCache = false)
@ -6209,12 +6243,12 @@ class Event extends AppModel
$this->Job->id = $jobId;
}
$failed_attributes = $failed_objects = $failed_object_attributes = 0;
$saved_attributes = $saved_objects = $saved_object_attributes = 0;
$failed_attributes = $failed_objects = $failed_object_attributes = $failed_reports = 0;
$saved_attributes = $saved_objects = $saved_object_attributes = $saved_reports = 0;
$items_count = 0;
$failed = array();
$recovered_uuids = array();
foreach (array('Attribute', 'Object') as $feature) {
foreach (array('Attribute', 'Object', 'EventReport') as $feature) {
if (isset($resolved_data[$feature])) {
$items_count += count($resolved_data[$feature]);
}
@ -6430,7 +6464,27 @@ class Event extends AppModel
}
}
}
if ($saved_attributes > 0 || $saved_objects > 0) {
if (!empty($resolved_data['EventReport'])) {
$total_reports = count($resolved_data['EventReport']);
foreach ($resolved_data['EventReport'] as $i => $report) {
$this->EventReport->create();
$report['event_id'] = $id;
if ($this->EventReport->save($report)) {
$saved_reports++;
} else {
$failed_reports++;
$lastReportError = $this->EventReport->validationErrors;
}
if ($jobId) {
$current = ($i + 1);
$this->Job->saveField('message', 'EventReport ' . $current . '/' . $total_reports);
$this->Job->saveField('progress', ($current * 100 / $items_count));
}
}
} else {
$total_reports = 0;
}
if ($saved_attributes > 0 || $saved_objects > 0 || $saved_reports > 0) {
$event = $this->find('first', array(
'conditions' => array('Event.id' => $id),
'recursive' => -1
@ -6443,7 +6497,7 @@ class Event extends AppModel
$this->save($event);
}
if ($event_level) {
return $saved_attributes + $saved_object_attributes;
return $saved_attributes + $saved_object_attributes + $saved_reports;
}
$message = '';
if ($saved_attributes > 0) {
@ -6489,6 +6543,17 @@ class Event extends AppModel
}
$message .= 'you can have a look at the module results view you just left, to compare.';
}
if ($saved_reports > 0) {
$message .= $saved_reports . ' ' . $this->__apply_inflector($saved_reports, 'eventReport') . ' created. ';
}
if ($failed_reports > 0) {
if ($failed_reports == 1) {
$reason = ' eventReport could not be saved. Reason for the failure: ' . json_encode($lastReportError) . ' ';
} else {
$reason = ' eventReport could not be saved. ';
}
$message .= $failed_reports . $reason;
}
if ($jobId) {
$this->Job->saveField('message', 'Processing complete. ' . $message);
$this->Job->saveField('progress', 100);
@ -6934,7 +6999,7 @@ class Event extends AppModel
'model_id' => 0,
'email' => 'SYSTEM',
'action' => 'error',
'title' => sprintf('Event fetch potential memory exhaustion. During the fetching of events, a large event (#%s) was detected that exceeds the available PHP memory. Consider raising the PHP max_memory setting to at least %sM', $largest_event_id, ceil($largest_event/$memory_scaling_factor)),
'title' => sprintf('Event fetch potential memory exhaustion.' . PHP_EOL . 'During the fetching of events, a large event (#%s) was detected that exceeds the available PHP memory.' . PHP_EOL . 'Consider raising the PHP max_memory setting to at least %sM', $largest_event_id, ceil($largest_event/$memory_scaling_factor)),
'change' => null,
));
}
@ -7118,7 +7183,7 @@ class Event extends AppModel
}
}
}
/**
* extractAllTagNames Returns all tag names attached to any elements in an event
*

View File

@ -103,6 +103,9 @@ class EventReport extends AppModel
$report = ['EventReport' => $report];
}
$report['EventReport']['event_id'] = $eventId;
if (!empty($report['EventReport']['id'])) {
unset($report['EventReport']['id']);
}
$report = $this->captureSG($user, $report);
$this->create();
$errors = $this->saveAndReturnErrors($report, ['fieldList' => $this->captureFields]);
@ -114,7 +117,7 @@ class EventReport extends AppModel
}
return $errors;
}
/**
* addReport Add a report
*
@ -131,7 +134,7 @@ class EventReport extends AppModel
}
return $errors;
}
/**
* editReport Edit a report
*
@ -208,7 +211,7 @@ class EventReport extends AppModel
}
return $errors;
}
/**
* restoreReport ACL-aware method to restore a report.
*
@ -235,7 +238,7 @@ class EventReport extends AppModel
}
return $report;
}
/**
* buildACLConditions Generate ACL conditions for viewing the report
*
@ -299,7 +302,7 @@ class EventReport extends AppModel
}
return array();
}
/**
* fetchReports ACL-aware method. Basically find with ACL
*
@ -391,7 +394,7 @@ class EventReport extends AppModel
}
return true;
}
public function reArrangeReport(array $report)
{
$rearrangeObjects = array('Event', 'SharingGroup');
@ -548,7 +551,7 @@ class EventReport extends AppModel
}
return $errors;
}
public function applySuggestionsInText($contentWithSuggestions, array $attribute, $value)
{
$textToBeReplaced = "@[suggestion]($value)";
@ -592,7 +595,7 @@ class EventReport extends AppModel
'attribute' => $savedAttribute
];
}
/**
* transformFreeTextIntoReplacement
*
@ -704,7 +707,7 @@ class EventReport extends AppModel
'replacementResult' => $replacementResult,
];
}
/**
* extractWithReplacements Extract context information from report with special care for ATT&CK
*

View File

@ -32,7 +32,10 @@ class Feed extends AppModel
'rule' => array('urlOrExistingFilepath')
),
'provider' => 'valueNotEmpty',
'name' => 'valueNotEmpty',
'name' => [
'rule' => 'valueNotEmpty',
'required' => true,
],
'event_id' => array(
'rule' => array('numeric'),
'message' => 'Please enter a numeric event ID or leave this field blank.',
@ -1469,7 +1472,7 @@ class Feed extends AppModel
}
}
$this->create();
if (!$this->save($feed, true, array('name', 'provider', 'url', 'rules', 'source_format', 'fixed_event', 'delta_merge', 'override_ids', 'publish', 'settings', 'tag_id', 'default', 'lookup_visible'))) {
if (!$this->save($feed, true, array('name', 'provider', 'url', 'rules', 'source_format', 'fixed_event', 'delta_merge', 'override_ids', 'publish', 'settings', 'tag_id', 'default', 'lookup_visible', 'headers'))) {
$results['fails']++;
} else {
$results['successes']++;

View File

@ -377,12 +377,23 @@ class Galaxy extends AppModel
$result = $this->Tag->$connectorModel->save($toSave);
if ($result) {
if ($target_type !== 'tag_collection') {
$date = new DateTime();
if ($target_type === 'event') {
$event = $target;
} else if ($target_type === 'attribute') {
$target['Attribute']['timestamp'] = $date->getTimestamp();
$this->Tag->AttributeTag->Attribute->save($target);
if (!empty($target['Attribute']['object_id'])) {
$container_object = $this->Tag->AttributeTag->Attribute->Object->find('first', [
'recursive' => -1,
'conditions' => ['id' => $target['Attribute']['object_id']]
]);
$container_object['Object']['timestamp'] = $date->getTimestamp();
$this->Tag->AttributeTag->Attribute->Object->save($container_object);
}
}
$this->Tag->EventTag->Event->insertLock($user, $event['Event']['id']);
$event['Event']['published'] = 0;
$date = new DateTime();
$event['Event']['timestamp'] = $date->getTimestamp();
$this->Tag->EventTag->Event->save($event);
}

View File

@ -415,7 +415,7 @@ class GalaxyCluster extends AppModel
}
$saveSuccess = $this->save($cluster, array('fieldList' => $fieldList));
if ($saveSuccess) {
if (!empty($cluster['GalaxyCluster']['GalaxyElement'])) {
if (isset($cluster['GalaxyCluster']['GalaxyElement'])) {
$elementsToSave = array();
foreach ($cluster['GalaxyCluster']['GalaxyElement'] as $element) { // transform cluster into Galaxy meta format
$elementsToSave[$element['key']][] = $element['value'];
@ -870,25 +870,23 @@ class GalaxyCluster extends AppModel
}
/**
* @param string $name
* @param string|int $name Cluster name or ID
* @param array $user
* @return array|mixed
*/
public function getCluster($name, $user)
{
$isGalaxyTag = strpos($name, 'misp-galaxy:') === 0;
if (!$isGalaxyTag) {
return null;
}
if (isset($this->__clusterCache[$name])) {
return $this->__clusterCache[$name];
}
$conditions = array();
if (is_numeric($name)) {
$conditions[] = array('GalaxyCluster.id' => $name);
$conditions = array('GalaxyCluster.id' => $name);
} else {
$conditions[] = array('LOWER(GalaxyCluster.tag_name)' => strtolower($name));
$isGalaxyTag = strpos($name, 'misp-galaxy:') === 0;
if (!$isGalaxyTag) {
return null;
}
$conditions = array('LOWER(GalaxyCluster.tag_name)' => strtolower($name));
}
$cluster = $this->fetchGalaxyClusters($user, array(
'conditions' => $conditions,

View File

@ -128,4 +128,14 @@ class GalaxyElement extends AppModel
}
return $elements;
}
public function getExpandedJSONFromElements($elements)
{
$keyedValue = [];
foreach ($elements as $i => $element) {
$keyedValue[$element['GalaxyElement']['key']][] = $element['GalaxyElement']['value'];
}
$expanded = Hash::expand($keyedValue);
return $expanded;
}
}

View File

@ -321,6 +321,17 @@ class MispObject extends AppModel
);
}
$newObjectAttributeCount = count($newObjectAttributes);
if (!empty($this->__objectDuplicationCheckCache['new'][$object['Object']['template_uuid']])) {
foreach ($this->__objectDuplicationCheckCache['new'][$object['Object']['template_uuid']] as $previousNewObject) {
if ($newObjectAttributeCount === count($previousNewObject)) {
if (empty(array_diff($previousNewObject, $newObjectAttributes))) {
return true;
}
}
}
}
$this->__objectDuplicationCheckCache['new'][$object['Object']['template_uuid']][] = $newObjectAttributes;
if (!isset($this->__objectDuplicationCheckCache[$object['Object']['template_uuid']])) {
$this->__objectDuplicationCheckCache[$object['Object']['template_uuid']] = $this->find('all', array(
'recursive' => -1,
@ -892,13 +903,13 @@ class MispObject extends AppModel
return $this->id;
}
public function captureObject($object, $eventId, $user, $log = false, $unpublish = true)
public function captureObject($object, $eventId, $user, $log = false, $unpublish = true, $breakOnDuplicate = false)
{
$this->create();
if (!isset($object['Object'])) {
$object = array('Object' => $object);
}
if (!empty($object['Object']['breakOnDuplicate'])) {
if (!empty($object['Object']['breakOnDuplicate']) || $breakOnDuplicate) {
$duplicate = $this->checkForDuplicateObjects($object, $eventId);
if ($duplicate) {
$log->create();
@ -912,8 +923,8 @@ class MispObject extends AppModel
'title' => 'Object dropped due to it being a duplicate and breakOnDuplicate being requested for Event ' . $eventId,
'change' => 'Duplicate object found.',
));
return true;
}
return true;
}
if (empty($log)) {
$log = ClassRegistry::init('Log');

View File

@ -31,6 +31,8 @@ class ObjectTemplate extends AppModel
public $validate = array(
);
public $objectsDir = APP . 'files/misp-objects/objects';
public function afterFind($results, $primary = false)
{
foreach ($results as $k => $result) {
@ -49,10 +51,9 @@ class ObjectTemplate extends AppModel
public function update($user = false, $type = false, $force = false)
{
$objectsDir = APP . 'files/misp-objects/objects';
$directories = glob($objectsDir . '/*', GLOB_ONLYDIR);
$directories = $this->getTemplateDirectoryPaths();
foreach ($directories as $k => $dir) {
$dir = str_replace($objectsDir, '', $dir);
$dir = str_replace($this->objectsDir, '', $dir);
$directories[$k] = $dir;
}
$updated = array();
@ -60,10 +61,10 @@ class ObjectTemplate extends AppModel
if ($type && '/' . $type != $dir) {
continue;
}
if (!file_exists($objectsDir . DS . $dir . DS . 'definition.json')) {
if (!file_exists($this->objectsDir . DS . $dir . DS . 'definition.json')) {
continue;
}
$file = new File($objectsDir . DS . $dir . DS . 'definition.json');
$file = new File($this->objectsDir . DS . $dir . DS . 'definition.json');
$template = json_decode($file->read(), true);
$file->close();
if (!isset($template['version'])) {
@ -316,4 +317,56 @@ class ObjectTemplate extends AppModel
}
return 1;
}
public function getRawFromDisk($uuidOrName)
{
$template = [];
if (Validation::uuid($uuidOrName)) {
foreach ($this->readTemplatesFromDisk() as $templateFromDisk) {
if ($templateFromDisk['uuid'] == $uuidOrName) {
$template = $templateFromDisk;
break;
}
}
} else {
$allTemplateNames = $this->getTemplateDirectoryPaths(false);
if (in_array($uuidOrName, $allTemplateNames)) { // ensure the path is not out of scope
$template = $this->readTemplateFromDisk($this->getFullPathFromTemplateName($uuidOrName));
}
}
return $template;
}
private function readTemplateFromDisk($path)
{
$file = new File($path, false);
if (!$file->exists()) {
return false;
}
$template = json_decode($file->read(), true);
$file->close();
return $template;
}
private function readTemplatesFromDisk()
{
foreach ($this->getTemplateDirectoryPaths() as $dirpath) {
$filepath = $dirpath . DS . 'definition.json';
$template = $this->readTemplateFromDisk($filepath);
if (isset($template['uuid'])) {
yield $template;
}
}
}
private function getTemplateDirectoryPaths($fullPath=true)
{
$dir = new Folder($this->objectsDir, false);
return $dir->read(true, false, $fullPath)[0];
}
private function getFullPathFromTemplateName($templateName)
{
return $this->objectsDir . DS . $templateName . DS . 'definition.json';
}
}

View File

@ -596,7 +596,8 @@ class Organisation extends AppModel
{
$countries = array_column($this->getCountryGalaxyCluster(), 'description');
sort($countries);
array_unshift($countries, 'Internation');
array_unshift($countries, 'International');
array_unshift($countries, 'Europe');
return $countries;
}
}

View File

@ -3435,6 +3435,32 @@ class Server extends AppModel
return $settings;
}
/**
* Return PHP setting in basic unit (bytes).
* @param string $setting
* @return string|int|null
*/
public function getIniSetting($setting)
{
$value = ini_get($setting);
if ($value === '') {
return null;
}
switch ($setting) {
case 'memory_limit':
case 'upload_max_filesize':
case 'post_max_size':
return (int)preg_replace_callback('/(-?\d+)(.?)/', function ($m) {
return $m[1] * pow(1024, strpos('BKMG', $m[2]));
}, strtoupper($value));
case 'max_execution_time':
return (int)$value;
default:
return $value;
}
}
public function killWorker($pid, $user)
{
if (!is_numeric($pid)) {
@ -5416,7 +5442,7 @@ class Server extends AppModel
),
'obscure_subject' => array(
'level' => 2,
'description' => __('When enabled, subject in signed and encrypted e-mails will not send in unencrypted form.'),
'description' => __('When enabled, the subject in signed and encrypted e-mails will not be sent in unencrypted form.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',
@ -5516,7 +5542,7 @@ class Server extends AppModel
'level' => 0,
'description' => __('Disabling this setting will remove all form tampering protection. Do not set this setting pretty much ever. You were warned.'),
'value' => false,
'errorMessage' => 'This setting leaves your users open to CSRF attacks. Do not please consider disabling this setting.',
'errorMessage' => 'This setting leaves your users open to CSRF attacks. Please consider disabling this setting.',
'test' => 'testBoolFalse',
'type' => 'boolean',
'null' => true
@ -5559,7 +5585,7 @@ class Server extends AppModel
],
'auth_enforced' => [
'level' => self::SETTING_OPTIONAL,
'description' => __('This optional can be enabled if external auth provider is used and when set to true, it will disable default form authentication.'),
'description' => __('This optionally can be enabled if an external auth provider is used. When set to true, it will disable the default form authentication.'),
'value' => false,
'errorMessage' => '',
'test' => 'testBool',

View File

@ -819,4 +819,49 @@ class ShadowAttribute extends AppModel
));
}
}
public function saveAttachment($shadowAttribute, $path_suffix='')
{
$result = $this->loadAttachmentTool()->saveShadow($shadowAttribute['event_id'], $shadowAttribute['id'], $shadowAttribute['data'], $path_suffix);
if ($result) {
$this->loadAttachmentScan()->backgroundScan(AttachmentScan::TYPE_SHADOW_ATTRIBUTE, $shadowAttribute);
}
return $result;
}
/**
* @param array $shadowAttribute
* @param bool $thumbnail
* @param int $maxWidth - When $thumbnail is true
* @param int $maxHeight - When $thumbnail is true
* @return string
* @throws Exception
*/
public function getPictureData(array $shadowAttribute, $thumbnail=false, $maxWidth=200, $maxHeight=200)
{
if ($thumbnail && extension_loaded('gd')) {
if ($maxWidth == 200 && $maxHeight == 200) {
// Return thumbnail directly if already exists
try {
return $this->getAttachment($shadowAttribute['ShadowAttribute'], $path_suffix = '_thumbnail');
} catch (NotFoundException $e) {
// pass
}
}
// Thumbnail doesn't exists, we need to generate it
$imageData = $this->getAttachment($shadowAttribute['ShadowAttribute']);
$imageData = $this->Attribute->resizeImage($imageData, $maxWidth, $maxHeight);
// Save just when requested default thumbnail size
if ($maxWidth == 200 && $maxHeight == 200) {
$shadowAttribute['ShadowAttribute']['data'] = $imageData;
$this->saveAttachment($shadowAttribute['ShadowAttribute'], $path_suffix='_thumbnail');
}
} else {
$imageData = $this->getAttachment($shadowAttribute['ShadowAttribute']);
}
return $imageData;
}
}

View File

@ -1,6 +1,10 @@
<?php
App::uses('AppModel', 'Model');
/**
* @property EventTag $EventTag
* @property AttributeTag $AttributeTag
*/
class Tag extends AppModel
{
public $useTable = 'tags';
@ -177,8 +181,8 @@ class Tag extends AppModel
{
$conditions = array();
if (!$user['Role']['perm_site_admin']) {
$conditions['Tag.org_id'] = array(0, $user['User']['org_id']);
$conditions['Tag.user_id'] = array(0, $user['User']['id']);
$conditions['Tag.org_id'] = array(0, $user['org_id']);
$conditions['Tag.user_id'] = array(0, $user['id']);
$conditions['Tag.hide_tag'] = 0;
}
return $this->find('all', array('conditions' => $conditions, 'recursive' => -1));

View File

@ -63,7 +63,7 @@ class TagCollection extends AppModel
return true;
}
public function fetchTagCollection($user, $params = array())
public function fetchTagCollection(array $user, $params = array())
{
if (empty($user['Role']['perm_site_admin'])) {
$params['conditions']['AND'][] = array(
@ -104,8 +104,17 @@ class TagCollection extends AppModel
return true;
}
public function cullBlockedTags($user, $tagCollections)
/**
* @param array $user
* @param array $tagCollections
* @return array|
*/
public function cullBlockedTags(array $user, array $tagCollections)
{
if (empty($tagCollections)) {
return [];
}
$single = false;
if (!isset($tagCollections[0])) {
$tagCollections = array(0 => $tagCollections);

View File

@ -228,7 +228,7 @@ class Taxonomy extends AppModel
// returns all tags associated to a taxonomy
// returns all tags not associated to a taxonomy if $inverse is true
public function getAllTaxonomyTags($inverse = false, $user = false, $full = false)
public function getAllTaxonomyTags($inverse = false, $user = false, $full = false, $hideUnselectable = true)
{
$this->Tag = ClassRegistry::init('Tag');
$taxonomyIdList = $this->find('column', array('fields' => array('Taxonomy.id')));
@ -243,7 +243,7 @@ class Taxonomy extends AppModel
$conditions[] = array('Tag.user_id' => array(0, $user['id']));
}
}
if (Configure::read('MISP.incoming_tags_disabled_by_default')) {
if (Configure::read('MISP.incoming_tags_disabled_by_default') || $hideUnselectable) {
$conditions['Tag.hide_tag'] = 0;
}
if ($full) {

View File

@ -230,25 +230,21 @@ class UserSetting extends AppModel
return null;
}
/*
* Check whether the event is something the user is interested (to be alerted on)
*
/**
* Check whether the event is something the user is interested (to be alerted on)
* @param $user
* @param $event
* @return bool
*/
public function checkPublishFilter($user, $event)
public function checkPublishFilter(array $user, array $event)
{
$rule = $this->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.user_id' => $user['id'],
'UserSetting.setting' => 'publish_alert_filter'
)
));
$rule = $this->getValueForUser($user['id'], 'publish_alert_filter');
// We should return true if no setting has been configured, or there's a setting with an empty value
if (empty($rule) || empty($rule['UserSetting']['value'])) {
if (empty($rule)) {
return true;
}
// recursively evaluate the boolean tree to true/false and return the value
$result = $this->__recursiveConvert($rule['UserSetting']['value'], $event);
$result = $this->__recursiveConvert($rule, $event);
if (isset($result[0])) {
return $result[0];
} else {
@ -256,7 +252,7 @@ class UserSetting extends AppModel
}
}
/*
/**
* Convert a complex rule set recursively
* takes as params a rule branch and an event to check against
* evaluate whether the rule set evaluates as true/false
@ -284,9 +280,9 @@ class UserSetting extends AppModel
}
}
}
$toReturn []= $temp;
$toReturn[] = $temp;
} else {
$toReturn []= $this->__checkEvent($k, $v, $event);
$toReturn[] = $this->__checkEvent($k, $v, $event);
}
}
return $toReturn;
@ -303,6 +299,7 @@ class UserSetting extends AppModel
* - Tag.name (checks against both event and attribute tags)
* - Orgc.uuid
* - Orgc.name
* - ThreatLevel.name
* Values passed can be used for direct string comparisons or alternatively
* as substring matches by encapsulating the string in a pair of "%" characters
* Each rule can take a list of values
@ -332,6 +329,8 @@ class UserSetting extends AppModel
Hash::extract($event, 'Object.{n}.Attribute.{n}.AttributeTag.{n}.Tag.name'),
Hash::extract($event, 'EventTag.{n}.Tag.name')
);
} else if ($rule === 'ThreatLevel.name') {
$values = [$event['ThreatLevel']['name']];
}
if (!empty($values)) {
foreach ($values as $extracted_value) {
@ -405,18 +404,14 @@ class UserSetting extends AppModel
return true;
}
/**
* @param int $user_id
* @param string $setting
* @return array|mixed
* @deprecated
*/
public function getSetting($user_id, $setting)
{
$setting = $this->find('first', array(
'recursive' => -1,
'conditions' => array(
'UserSetting.user_id' => $user_id,
'UserSetting.setting' => $setting
)
));
if (empty($setting)) {
return array();
}
return $setting['UserSetting']['value'];
return $this->getValueForUser($user_id, $setting) ?: [];
}
}

View File

@ -1,5 +1,6 @@
<?php
App::uses('AppModel', 'Model');
App::uses('CidrTool', 'Tools');
/**
* @property WarninglistType $WarninglistType
@ -154,7 +155,7 @@ class Warninglist extends AppModel
if (!empty($saveToCache)) {
$pipe = $redis->multi(Redis::PIPELINE);
foreach ($saveToCache as $attributeKey => $json) {
$redis->setex($attributeKey, 3600, $json); // cache for one hour
$redis->setex($attributeKey, 8 * 3600, $json); // cache for eight hour
}
$pipe->exec();
}
@ -164,6 +165,12 @@ class Warninglist extends AppModel
public function update()
{
$existingWarninglist = $this->find('all', [
'fields' => ['id', 'name', 'version', 'enabled'],
'recursive' => -1,
]);
$existingWarninglist = array_column(array_column($existingWarninglist, 'Warninglist'), null, 'name');
$directories = glob(APP . 'files' . DS . 'warninglists' . DS . 'lists' . DS . '*', GLOB_ONLYDIR);
$updated = array('success' => [], 'fails' => []);
foreach ($directories as $dir) {
@ -179,17 +186,13 @@ class Warninglist extends AppModel
} elseif (is_array($list['type'])) {
$list['type'] = $list['type'][0];
}
$current = $this->find('first', array(
'conditions' => array('name' => $list['name']),
'recursive' => -1,
'fields' => array('*')
));
if (empty($current) || $list['version'] > $current['Warninglist']['version']) {
if (!isset($existingWarninglist[$list['name']]) || $list['version'] > $existingWarninglist[$list['name']]['version']) {
$current = isset($existingWarninglist[$list['name']]) ? $existingWarninglist[$list['name']] : [];
$result = $this->__updateList($list, $current);
if (is_numeric($result)) {
$updated['success'][$result] = array('name' => $list['name'], 'new' => $list['version']);
if (!empty($current)) {
$updated['success'][$result]['old'] = $current['Warninglist']['version'];
$updated['success'][$result]['old'] = $current['version'];
}
} else {
$updated['fails'][] = array('name' => $list['name'], 'fail' => json_encode($result));
@ -221,10 +224,10 @@ class Warninglist extends AppModel
$list['enabled'] = 0;
$warninglist = array();
if (!empty($current)) {
if ($current['Warninglist']['enabled']) {
if ($current['enabled']) {
$list['enabled'] = 1;
}
$this->quickDelete($current['Warninglist']['id']);
$this->quickDelete($current['id']);
}
$fieldsToSave = array('name', 'version', 'description', 'type', 'enabled');
foreach ($fieldsToSave as $fieldToSave) {
@ -398,39 +401,6 @@ class Warninglist extends AppModel
}
}
/**
* Filter out invalid IPv4 or IPv4 CIDR and append maximum netmaks if no netmask is given.
* @param array $inputValues
* @return array
*/
private function filterCidrList($inputValues)
{
$outputValues = [];
foreach ($inputValues as $v) {
$v = strtolower($v);
$parts = explode('/', $v, 2);
if (filter_var($parts[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
$maximumNetmask = 32;
} else if (filter_var($parts[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
$maximumNetmask = 128;
} else {
// IP address part of CIDR is invalid
continue;
}
if (!isset($parts[1])) {
// If CIDR doesnt contains '/', we will consider CIDR as /32 for IPv4 or /128 for IPv6
$v = "$v/$maximumNetmask";
} else if ($parts[1] > $maximumNetmask || $parts[1] < 0) {
// Netmask part of CIDR is invalid
continue;
}
$outputValues[$v] = true;
}
return $outputValues;
}
/**
* For 'hostname', 'string' and 'cidr' warninglist type, values are just in keys to save memory.
*
@ -459,7 +429,7 @@ class Warninglist extends AppModel
}
$values = $output;
} else if ($warninglist['Warninglist']['type'] === 'cidr') {
$values = $this->filterCidrList($values);
$values = new CidrTool($values);
}
$this->entriesCache[$id] = $values;
@ -497,7 +467,7 @@ class Warninglist extends AppModel
}
/**
* @param array $listValues
* @param array|CidrTool $listValues
* @param string $value
* @param string $type
* @param string $listType
@ -512,7 +482,7 @@ class Warninglist extends AppModel
}
foreach ($value as $v) {
if ($listType === 'cidr') {
$result = $this->__evalCidrList($listValues, $v);
$result = $listValues->contains($v);
} elseif ($listType === 'string') {
$result = $this->__evalString($listValues, $v);
} elseif ($listType === 'substring') {
@ -536,75 +506,6 @@ class Warninglist extends AppModel
return $this->__checkValue($listValues, $value, '', $type) !== false;
}
private function __evalCidrList($listValues, $value)
{
$valueMask = null;
if (strpos($value, '/') !== false) {
list($value, $valueMask) = explode('/', $value);
}
$match = false;
if (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
// This code converts IP address to all possible CIDRs that can contains given IP address
// and then check if given hash table contains that CIDR.
$ip = ip2long($value);
// Start from 1, because doesn't make sense to check 0.0.0.0/0 match
for ($bits = 1; $bits <= 32; $bits++) {
$mask = -1 << (32 - $bits);
$needle = long2ip($ip & $mask) . "/$bits";
if (isset($listValues[$needle])) {
$match = $needle;
break;
}
}
} elseif (filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
foreach ($listValues as $lv => $foo) {
if (strpos($lv, ':') !== false) { // Filter out IPv4 CIDR, IPv6 CIDR must contain colon
if ($this->__ipv6InCidr($value, $lv)) {
$match = $lv;
break;
}
}
}
}
if ($match && $valueMask) {
$matchMask = explode('/', $match)[1];
if ($valueMask < $matchMask) {
return false;
}
}
return $match;
}
/**
* Using solution from https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/IpUtils.php
*
* @param string $ip
* @param string $cidr
* @return bool
*/
private function __ipv6InCidr($ip, $cidr)
{
list($address, $netmask) = explode('/', $cidr);
$bytesAddr = unpack('n*', inet_pton($address));
$bytesTest = unpack('n*', inet_pton($ip));
for ($i = 1, $ceil = ceil($netmask / 16); $i <= $ceil; ++$i) {
$left = $netmask - 16 * ($i - 1);
$left = ($left <= 16) ? $left : 16;
$mask = ~(0xffff >> $left) & 0xffff;
if (($bytesAddr[$i] & $mask) != ($bytesTest[$i] & $mask)) {
return false;
}
}
return true;
}
/**
* Check for exact match.
*

41
app/Test/CidrToolTest.php Normal file
View File

@ -0,0 +1,41 @@
<?php
require_once __DIR__ . '/../Lib/Tools/CidrTool.php';
use PHPUnit\Framework\TestCase;
class CidrToolTest extends TestCase
{
public function testEmptyList(): void
{
$cidrTool = new CidrTool([]);
$this->assertFalse($cidrTool->contains('1.2.3.4'));
}
public function testIpv4Fullmask(): void
{
$cidrTool = new CidrTool(['1.2.3.4/32']);
$this->assertEquals('1.2.3.4/32', $cidrTool->contains('1.2.3.4'));
}
public function testIpv4WithoutNetmask(): void
{
$cidrTool = new CidrTool(['1.2.3.4']);
$this->assertEquals('1.2.3.4/32', $cidrTool->contains('1.2.3.4'));
}
public function testIpv4(): void
{
$cidrTool = new CidrTool(['10.0.0.0/8', '8.0.0.0/8', '9.0.0.0/8']);
$this->assertEquals('8.0.0.0/8', $cidrTool->contains('8.8.8.8'));
$this->assertFalse($cidrTool->contains('::1'));
$this->assertFalse($cidrTool->contains('7.1.2.3'));
}
public function testIpv6(): void
{
$cidrTool = new CidrTool(['2001:0db8:1234::/48']);
$this->assertEquals('2001:db8:1234::/48', $cidrTool->contains('2001:0db8:1234:0000:0000:0000:0000:0000'));
$this->assertEquals('2001:db8:1234::/48', $cidrTool->contains('2001:0db8:1234:ffff:ffff:ffff:ffff:ffff'));
$this->assertFalse($cidrTool->contains('2002:0db8:1234:ffff:ffff:ffff:ffff:ffff'));
}
}

View File

@ -29,9 +29,10 @@
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
$paginator = $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
$paginator .= $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
$paginator .= $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $paginator;
?>
</ul>
</div>
@ -91,6 +92,7 @@
if (!empty($attribute['Attribute']['RelatedAttribute'])) {
$event['RelatedAttribute'] = array($attribute['Attribute']['id'] => $attribute['Attribute']['RelatedAttribute']);
}
$attribute['Attribute']['objectType'] = 'attribute';
echo $this->element('/Events/View/row_attribute', array(
'object' => $attribute['Attribute'],
'k' => $k,
@ -124,24 +126,18 @@
</p>
<div class="pagination">
<ul>
<?php
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 20, 'separator' => '', 'tag' => 'li', 'currentClass' => 'active', 'currentTag' => 'span'));
echo $this->Paginator->next(__('next') . ' &raquo;', array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'next disabled', 'escape' => false, 'disabledTag' => 'span'));
?>
<?= $paginator ?>
</ul>
</div>
</div>
<?php
if ($isSearch == 1){
if ($isSearch == 1) {
$class = 'searchAttributes2';
} else {
$class = 'listAttributes';
}
?>
<?php
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event-collection', 'menuItem' => $class));
?>
<?= $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event-collection', 'menuItem' => $class)); ?>
<script type="text/javascript">
// tooltips
$(function () {

View File

@ -10,6 +10,9 @@ if (isset($keyUsage)) {
$dateAsString = date('Y-m-d', $date);
$keyUsageCsv .= $dateAsString . ',' . (isset($keyUsage[$dateAsString]) ? $keyUsage[$dateAsString] : 0) . '\n';
}
} else {
$lastUsed = null;
$uniqueIps = null;
}
echo $this->element(
@ -63,7 +66,7 @@ echo $this->element(
],
[
'key' => __('Last used'),
'raw' => $lastUsed ? date('Y-m-d H:i:s', $lastUsed) : __('Not used yet'),
'raw' => $lastUsed ? $this->Time->time($lastUsed) : __('Not used yet'),
'requirement' => isset($keyUsage),
],
[

View File

@ -91,12 +91,3 @@
));
echo '</div>';
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'dashboard', 'menuItem' => 'dashboardTemplateIndex'));
?>
<script type="text/javascript">
var passedArgsArray = <?php echo json_encode($passedArgs); ?>;
$(document).ready(function() {
$('#quickFilterButton').click(function() {
runIndexQuickFilter();
});
});
</script>

View File

@ -8,7 +8,7 @@
?>
</div>
<script type="text/javascript">
$(document).ready(function() {
$(function() {
if (<?= $config['autoRefreshDelay'] ? 'true' : 'false' ?>) {
setTimeout( function(){
updateDashboardWidget("#widget_<?= h($widget_id) ?>")},

View File

@ -94,7 +94,7 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
if (!empty($extended)):
if ($object['event_id'] != $event['Event']['id']):
$extensionOrg = $event['extensionEvents'][$object['event_id']]['Orgc'];
echo $this->OrgImg->getOrgLogo($extensionOrg['name'], 24);
echo $this->OrgImg->getOrgLogo($extensionOrg, 24);
else:
echo $this->OrgImg->getOrgLogo($event['Orgc'], 24);
endif;
@ -211,16 +211,16 @@ $quickEdit = function($fieldName) use ($editScope, $object, $event) {
if (isset($object['Feed'])) {
foreach ($object['Feed'] as $feed) {
$relatedData = array(
__('Name') => $feed['name'],
__('URL') => $feed['url'],
__('Provider') => $feed['provider'],
__('Name') => h($feed['name']),
__('URL') => h($feed['url']),
__('Provider') => h($feed['provider']),
);
if (isset($feed['event_uuids'])) {
$relatedData[__('Event UUIDs')] = implode('<br>', $feed['event_uuids']);
$relatedData[__('Event UUIDs')] = implode('<br>', array_map('h', $feed['event_uuids']));
}
$popover = '';
foreach ($relatedData as $k => $v) {
$popover .= '<span class="bold black">' . h($k) . '</span>: <span class="blue">' . h($v) . '</span><br>';
$popover .= '<span class="bold black">' . $k . '</span>: <span class="blue">' . $v . '</span><br>';
}
if ($isSiteAdmin || $hostOrgUser) {
if ($feed['source_format'] === 'misp') {
@ -418,4 +418,3 @@ if (!empty($object['ShadowAttribute'])) {
));
}
}

View File

@ -115,23 +115,35 @@
?>
<td class="short action-links">
<?php
if ($mayModify && empty($object['deleted'])) {
echo sprintf(
'<a href="%s/objects/edit/%s" title="%s" aria-label="%s" class="fa fa-edit white useCursorPointer"></a> ',
$baseurl,
h($object['id']),
__('Edit'),
__('Edit')
);
echo sprintf(
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onClick="%2$s"></span>',
(empty($event['Event']['publish_timestamp']) ? __('Permanently delete object') : __('Soft delete object')),
sprintf(
'deleteObject(\'objects\', \'delete\', \'%s\', \'%s\');',
empty($event['Event']['publish_timestamp']) ? h($object['id']) . '/true' : h($object['id']),
h($event['Event']['id'])
)
);
if ($mayModify) {
if (empty($object['deleted'])) {
echo sprintf(
'<a href="%s/objects/edit/%s" title="%s" aria-label="%s" class="fa fa-edit white useCursorPointer"></a> ',
$baseurl,
h($object['id']),
__('Edit'),
__('Edit')
);
echo sprintf(
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onClick="%2$s"></span>',
(empty($event['Event']['publish_timestamp']) ? __('Permanently delete object') : __('Soft delete object')),
sprintf(
'deleteObject(\'objects\', \'delete\', \'%s\', \'%s\');',
empty($event['Event']['publish_timestamp']) ? h($object['id']) . '/true' : h($object['id']),
h($event['Event']['id'])
)
);
} else {
echo sprintf(
'<span class="fa fa-trash white useCursorPointer" title="%1$s" role="button" tabindex="0" aria-label="%1$s" onClick="%2$s"></span>',
__('Permanently delete object'),
sprintf(
'deleteObject(\'objects\', \'delete\', \'%s\', \'%s\');',
h($object['id']) . '/true',
h($event['Event']['id'])
)
);
}
}
?>
</td>
@ -151,4 +163,3 @@
}
echo '<tr class="objectAddFieldTr"><td><span class="fa fa-plus-circle objectAddField" title="' . __('Add an Object Attribute') .'" onclick="popoverPopup(this, ' . h($object['id']) . ', \'objects\', \'quickFetchTemplateWithValidObjectAttributes\')"></span></td></tr>';
}

View File

@ -1,7 +1,12 @@
<?php if ($object['first_seen'] != null || $object['last_seen'] != null): ?>
<?php
$time = function ($value) {
return $value != null ? $this->Time->time($value) : '<span style="display: block; text-align:center;">_</span>';
};
if ($object['first_seen'] != null || $object['last_seen'] != null): ?>
<div>
<div><?php echo $object['first_seen'] != null ? h($object['first_seen']) : '<span style="display: block; text-align:center;">_</span>'; ?></div>
<div><?= $time($object['first_seen']) ?></div>
<i style="display: block; text-align: center;" class="fas fa-arrow-down"></i>
<div><?php echo $object['last_seen'] != null ? h($object['last_seen']) : '<span style="display: block; text-align:center;">_</span>'; ?></div>
<div><?= $time($object['last_seen']) ?></div>
</div>
<?php endif ?>

View File

@ -9,9 +9,9 @@ if (isset($sightingsData['data'][$objectId])) {
foreach ($typeData['orgs'] as $org => $orgData) {
$extra = $org === $me['Organisation']['name'] ? ' class="bold"' : "";
if ($type == 'expiration') {
$html .= '<span' . $extra . '>' . h($org) . '</span>: <span class="orange bold">' . date('Y-m-d H:i:s', $orgData['date']) . '</span><br>';
$html .= '<span' . $extra . '>' . h($org) . '</span>: <span class="orange bold">' . $this->Time->time($orgData['date']) . '</span><br>';
} else {
$html .= '<span' . $extra . '>' . h($org) . '</span>: <span class="' . ($type === 'sighting' ? 'green' : 'red') . ' bold">' . h($orgData['count']) . ' (' . date('Y-m-d H:i:s', $orgData['date']) . ')</span><br>';
$html .= '<span' . $extra . '>' . h($org) . '</span>: <span class="' . ($type === 'sighting' ? 'green' : 'red') . ' bold">' . h($orgData['count']) . ' (' . $this->Time->time($orgData['date']) . ')</span><br>';
}
}
}

View File

@ -28,7 +28,7 @@ switch ($object['type']) {
if ($object['type'] === 'attachment' && isset($object['image'])) {
if ($object['image'] === true) {
$img = '<it class="fa fa-spin fa-spinner" style="font-size: large; left: 50%; top: 50%;"></it>';
$img .= '<img class="screenshot screenshot-collapsed useCursorPointer img-rounded hidden" src="' . $baseurl . '/attributes/viewPicture/' . h($object['id']) . '/1' . '" title="' . h($object['value']) . '" onload="$(this).show(200); $(this).parent().find(\'.fa-spinner\').remove();"/>';
$img .= '<img class="screenshot screenshot-collapsed useCursorPointer img-rounded hidden" src="' . $baseurl . sprintf('/%s/viewPicture/', $object['objectType'] == 'proposal' ? 'shadowAttributes' : 'attributes') . h($object['id']) . '/1' . '" title="' . h($object['value']) . '" onload="$(this).show(200); $(this).parent().find(\'.fa-spinner\').remove();"/>';
echo $img;
} else {
$extension = pathinfo($object['value'], PATHINFO_EXTENSION);
@ -70,6 +70,9 @@ switch ($object['type']) {
}
}
break;
case 'datetime':
echo $this->Time->time($object['value']);
break;
case 'vulnerability':
$cveUrl = Configure::read('MISP.cveurl') ?: 'https://cve.circl.lu/cve/';

View File

@ -93,7 +93,7 @@
<td style="width:30px;">
<a href="<?php echo $baseurl."/events/view/".$event['Event']['id'] ?>"><?php echo $event['Event']['id'];?></a>
</td>
<td class="shortish">
<td class="short">
<?php
$galaxies = array();
if (!empty($event['GalaxyCluster'])) {

View File

@ -22,6 +22,11 @@ echo $this->element('genericElements/assetLoader', array(
return;
}
hasBeenBuilt = true;
var $tree = $('#treeSVG');
treeWidth = $tree.width() - margin.right - margin.left;
treeHeight = $tree.height() - margin.top - margin.bottom;
var leftShift;
var childrenBothSides, side;
if (treeData.left[0].children === undefined || treeData.left[0].children.length == 0) {
leftShift = 0;
childrenBothSides = false;
@ -38,11 +43,6 @@ echo $this->element('genericElements/assetLoader', array(
}
}
adaptContainerHeightIfNeeded(side);
var $tree = $('#treeSVG');
treeWidth = $tree.width() - margin.right - margin.left;
treeHeight = $tree.height() - margin.top - margin.bottom;
var leftShift;
var childrenBothSides, side;
var data = genHierarchy(treeData, leftShift, childrenBothSides, side);
drawTree(data, leftShift, childrenBothSides);

View File

@ -27,7 +27,7 @@
</td>
<td class="short">
<div id = "Attribute_<?php echo $object['id']; ?>_category_placeholder" class = "inline-field-placeholder"></div>
<div id = "Attribute_<?php echo $object['id']; ?>_category_solid" class="inline-field-solid" ondblclick="activateField('Attribute', '<?php echo $object['id']; ?>', 'category', <?php echo $event['Event']['id'];?>);">
<div id = "Attribute_<?php echo $object['id']; ?>_category_solid" class="inline-field-solid">
<?php echo h($object['category']); ?>
</div>
</td>
@ -41,31 +41,16 @@
?>
<div></div>
<div id = "Attribute_<?php echo $object['id']; ?>_type_placeholder" class = "inline-field-placeholder"></div>
<div id = "Attribute_<?php echo $object['id']; ?>_type_solid" class="inline-field-solid" ondblclick="activateField('Attribute', '<?php echo $object['id']; ?>', 'type', <?php echo $event['Event']['id'];?>);">
<div id = "Attribute_<?php echo $object['id']; ?>_type_solid" class="inline-field-solid">
<?php echo h($object['type']); ?>
</div>
</td>
<td id="Attribute_<?php echo h($object['id']); ?>_container" class="showspaces limitedWidth shortish">
<div id="Attribute_<?php echo $object['id']; ?>_value_placeholder" class="inline-field-placeholder"></div>
<?php
if ('attachment' !== $object['type'] && 'malware-sample' !== $object['type']) $editable = ' ondblclick="activateField(\'Attribute\', \'' . $object['id'] . '\', \'value\', \'' . $event['Event']['id'] . '\');"';
else $editable = '';
?>
<div id = "Attribute_<?php echo $object['id']; ?>_value_solid" class="inline-field-solid" <?php echo $editable; ?>>
<div id = "Attribute_<?php echo $object['id']; ?>_value_solid" class="inline-field-solid">
<span <?php if (Configure::read('Plugin.Enrichment_hover_enable') && isset($modules) && isset($modules['hover_type'][$object['type']])) echo 'class="eventViewAttributeHover" data-object-type="Attribute" data-object-id="' . h($object['id']) . '"'?>>
<?php
echo $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass));
?>
<?= $this->element('/Events/View/value_field', array('object' => $object, 'linkClass' => $linkClass)); ?>
</span>
<?php
if (isset($object['warnings'])) {
$temp = '';
foreach ($object['warnings'] as $warning) {
$temp .= '<span class="bold">' . h($warning['match']) . ':</span> <span class="red">' . h($warning['warninglist_name']) . '</span><br>';
}
echo ' <span aria-label="' . __('warning') . '" role="img" tabindex="0" class="fa fa-exclamation-triangle" data-placement="right" data-toggle="popover" data-content="' . h($temp) . '" data-trigger="hover" data-placement="right">&nbsp;</span>';
}
?>
</div>
</td>
<td class="shortish">
@ -78,7 +63,7 @@
</td>
<td class="showspaces bitwider">
<div id = "Attribute_<?php echo $object['id']; ?>_comment_placeholder" class = "inline-field-placeholder"></div>
<div id = "Attribute_<?php echo $object['id']; ?>_comment_solid" class="inline-field-solid" ondblclick="activateField('Attribute', '<?php echo $object['id']; ?>', 'comment', <?php echo $event['Event']['id'];?>);">
<div id = "Attribute_<?php echo $object['id']; ?>_comment_solid" class="inline-field-solid">
<?php echo nl2br(h($object['comment'])); ?>&nbsp;
</div>
</td>
@ -136,7 +121,7 @@
</td>
<td class="short">
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_placeholder" class = "inline-field-placeholder"></div>
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_solid" class="inline-field-solid" ondblclick="activateField('Attribute', '<?php echo $object['id']; ?>', 'to_ids', <?php echo $event['Event']['id'];?>);">
<div id = "Attribute_<?php echo $object['id']; ?>_to_ids_solid" class="inline-field-solid">
<?php echo $object['to_ids'] ? __('Yes') : __('No'); ?>
</div>
</td>

View File

@ -12,10 +12,7 @@
<ul>
<?php
$this->Paginator->options(array(
'url' => array($server['Server']['id'], $event['Event']['id']),
'evalScripts' => true,
'before' => '$(".progress").show()',
'complete' => '$(".progress").hide()',
'url' => array($server['Server']['id'], $event['Event']['id']),
));
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 60, 'separator' => '', 'tag' => 'li', 'currentClass' => 'red', 'currentTag' => 'span'));
@ -79,10 +76,7 @@
<ul>
<?php
$this->Paginator->options(array(
'url' => array($server['Server']['id'], $event['Event']['id']),
'evalScripts' => true,
'before' => '$(".progress").show()',
'complete' => '$(".progress").hide()',
'url' => array($server['Server']['id'], $event['Event']['id']),
));
echo $this->Paginator->prev('&laquo; ' . __('previous'), array('tag' => 'li', 'escape' => false), null, array('tag' => 'li', 'class' => 'prev disabled', 'escape' => false, 'disabledTag' => 'span'));
echo $this->Paginator->numbers(array('modulus' => 60, 'separator' => '', 'tag' => 'li', 'currentClass' => 'red', 'currentTag' => 'span'));
@ -105,7 +99,7 @@
var currentUri = "<?php echo isset($currentUri) ? h($currentUri) : $baseurl . '/servers/previewEvent/' . h($server['Server']['id']) . '/' . h($event['Event']['id']); ?>";
var lastSelected = false;
var deleted = <?php echo (isset($deleted) && $deleted) ? 'true' : 'false';?>;
$(document).ready(function() {
$(function() {
<?php
if ($focusedRow !== false):
?>
@ -118,6 +112,3 @@
});
});
</script>
<?php
echo $this->Js->writeBuffer();
?>

View File

@ -0,0 +1,14 @@
<?php
echo $this->element('genericElements/IndexTable/index_table', [
'data' => [
'data' => $data['data'],
'top_bar' => [],
'fields' => $data['fields'],
'title' => false,
'description' => false,
'pull' => 'right',
'skip_pagination' => true,
'actions' => []
]
]);
?>

View File

@ -78,7 +78,7 @@
'fa-icon' => 'rebel',
'fa-source' => 'fab',
'onClick' => 'popoverPopup',
'onClickParams' => array('this', 'selected/attribute', 'galaxies', 'selectGalaxyNamespace')
'onClickParams' => array('this', 'selected/attribute/eventid:' . h($event['Event']['id']), 'galaxies', 'selectGalaxyNamespace')
),
array(
'id' => 'group-into-object-button',

View File

@ -29,7 +29,7 @@
?>
</div>
<div class="footerText footerCenterText">
<span><?php echo h(Configure::read('MISP.footermidleft')); ?> Powered by <a href="https://github.com/MISP/MISP">MISP <?php if (isset($me['id'])) echo h($mispVersionFull);?></a> <?php echo h(Configure::read('MISP.footermidright')); ?> - <?php echo date("Y-m-d H:i:s"); ?></span>
<span><?= h(Configure::read('MISP.footermidleft')); ?> Powered by <a href="https://github.com/MISP/MISP" rel="noopener">MISP <?= isset($me['id']) ? h($mispVersionFull) : '' ?></a> <?= h(Configure::read('MISP.footermidright')); ?> - <?= $this->Time->time(time()) ?></span>
</div>
<div class="pull-right" style="position:relative;padding-top:9px;z-index:2;">
<?php

View File

@ -1,5 +1,4 @@
<?php echo $this->Html->script('moment-with-locales'); ?>
<?= $this->Html->script('moment.min'); ?>
<script>
<?php
$temp = explode('_', $this->params->controller);
@ -49,22 +48,22 @@ $(function() {
var $sliders_container = $("#bothSeenSliderContainer");
var inputs_container = $('<div class="input-group input-daterange"></div>');
// create separate date and time input
var date_div_fs = $('<div class="input clear" style="width: 257px"></div>').append(
var date_div_fs = $('<div class="input clear" style="width: 257px; margin-right: 0"></div>').append(
$('<label><?php echo __('First seen date') . '<span class="fas fa-calendar label-icon"></span>'; ?><input id="date_fs" type="text" style="width: 240px;"></input></label>')
);
$(inputs_container).append(date_div_fs);
var date_div_ls = $('<div class="input text" style="width: 257px"></div>').append(
var date_div_ls = $('<div class="input text" style="width: 257px; margin-right: 0"></div>').append(
$('<label><?php echo __('Last seen date') . '<span class="fas fa-calendar label-icon"></span>'; ?><input id="date_ls" type="text" style="width: 240px;"></input></label>')
);
$(inputs_container).append(date_div_ls);
$sliders_container.append(inputs_container);
var time_div_fs = $('<div class="input clear" style="width: 257px"></div>').append(
var time_div_fs = $('<div class="input clear" style="width: 257px; margin-right: 0"></div>').append(
$('<label><?php echo __('First seen time') . '<span class="fas fa-clock label-icon"></span>'; ?><input id="time_fs" type="text" style="width: 240px; text-align: center; margin-bottom: 0px" placeholder="HH:MM:SS.ssssss+TT:TT"></input></label>'),
$('<span class="apply_css_arrow"></span>').text('<?php echo __('Expected format: HH:MM:SS.ssssss+TT:TT') ?>')
);
$sliders_container.append(time_div_fs);
var time_div_ls = $('<div class="input" style="width: 257px"></div>').append(
var time_div_ls = $('<div class="input" style="width: 257px; margin-right: 0"></div>').append(
$('<label><?php echo __('Last seen time') . '<span class="fas fa-clock label-icon"></span>'; ?><input id="time_ls" type="text" style="width: 240px; text-align: center; margin-bottom: 0px" placeholder="HH:MM:SS.ssssss+TT:TT"></input></label>'),
$('<span class="apply_css_arrow"></span>').text('<?php echo __('Expected format: HH:MM:SS.ssssss+TT:TT') ?>')
);

View File

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

View File

@ -14,11 +14,7 @@
if (empty($data) && !empty($field['empty'])) {
$data = $field['empty'];
}
if (is_numeric($data)) {
$data = date('Y-m-d H:i:s', $data);
} else {
$data = h($data);
}
$data = $this->Time->time($data);
if (!empty($field['onClick'])) {
$data = sprintf(
'<span onClick="%s">%s</span>',

View File

@ -23,7 +23,7 @@
$diffInDays = floor(($data - time()) / (3600 * 24));
$class = $diffInDays <= 14 ? 'text-warning bold' : 'text-success';
$title = __n('Will expire in %s day', 'Will expire in %s days', $diffInDays, $diffInDays);
$data = '<span class="' . $class . '" title="' . $title . '">' . date('Y-m-d H:i:s', $data) . '</span>';
$data = '<span class="' . $class . '" title="' . $title . '">' . $this->Time->time($data) . '</span>';
}
}
}

View File

@ -0,0 +1,13 @@
<?php
$value = Hash::get($row, $field['data_path']);
$key = Hash::get($row, $field['elementParams']['data_path_key']);
if ($key === 'refs' &&
(substr($value, 0, 8) === 'https://' || substr($value, 0, 7) === 'http://')
) {
echo '<a href="' . h($value) . '" rel="noreferrer noopener">' . h($value) . '</a>';
} else if ($key === 'country') {
echo $this->Icon->countryFlag($item['GalaxyElement']['value']) . ' ' . h($value);
} else {
echo h($value);
}

View File

@ -1,3 +1,3 @@
<?php
$value = Hash::extract($data, $field['path'])[0];
echo date('Y-m-d H:i:s', $value);
echo $this->Time->time($value);

View File

@ -22,7 +22,8 @@
'functionName' => '', // function to be called on submit
'submitButtonText' => 'Submit',
'disabledSubmitButton' => false, // wether to not draw the submit button
'flag_redraw_chosen' => false // should chosen picker be redraw at drawing time
'flag_redraw_chosen' => false, // should chosen picker be redraw at drawing time
'redraw_debounce_time' => 200,
);
/**
* Supported default option in <Option> fields:
@ -98,11 +99,11 @@ function setupChosen(id, redrawChosen) {
// hack to add template into the div
var $chosenContainer = $elem.parent().find('.chosen-container');
$elem.on('chosen:searchdone chosen:picked keyup change', function(e) {
redrawChosenWithTemplate($elem, $chosenContainer, e.type)
redrawChosenWithTemplateDebounced(true, $elem, $chosenContainer, e.type)
});
if (redrawChosen) {
redrawChosenWithTemplate($elem, $chosenContainer);
redrawChosenWithTemplateDebounced(false, $elem, $chosenContainer);
}
if ($elem.prop('multiple')) {
@ -112,6 +113,23 @@ function setupChosen(id, redrawChosen) {
}
}
var debounceTimer;
function redrawChosenWithTemplateDebounced(useDebounce, $select, $chosenContainer, eventType) {
if (useDebounce) {
clearTimeout(debounceTimer);
var timerValue = <?= $defaults['redraw_debounce_time'] ?>;
var resultCount = $select.data('chosen').search_results.children().length;
if (resultCount <= 20) {
timerValue = 0
}
debounceTimer = setTimeout(function() {
redrawChosenWithTemplate($select, $chosenContainer, eventType);
}, timerValue);
} else {
redrawChosenWithTemplate($select, $chosenContainer, eventType);
}
}
function redrawChosenWithTemplate($select, $chosenContainer, eventType) {
var optionLength = $select.find('option').length;
if (optionLength > 1000) {

View File

@ -160,11 +160,11 @@
<p><?php echo __('The following settings might have a negative impact on certain functionalities of MISP with their current and recommended minimum settings. You can adjust these in your php.ini. Keep in mind that the recommendations are not requirements, just recommendations. Depending on usage you might want to go beyond the recommended values.');?></p>
<?php
foreach ($phpSettings as $settingName => &$phpSetting):
echo $settingName . ' (<span class="bold">' . $phpSetting['value'] . ($phpSetting['unit'] ? $phpSetting['unit'] : '') . '</span>' .')' . '…';
echo $settingName . ' (<b>' . $phpSetting['value'] . ($phpSetting['unit'] ? ' ' . $phpSetting['unit'] : '') . '</b>' .')' . '…';
if ($phpSetting['value'] < $phpSetting['recommended']) $pass = false;
else $pass = true;
?>
<span style="color:<?php echo $pass ? 'green': 'orange'; ?>"><?php echo $pass ? __('OK') : __('Low'); ?> (recommended: <?php echo strval($phpSetting['recommended']) . ($phpSetting['unit'] ? $phpSetting['unit'] : '') . ')'; ?></span><br />
<span style="color:<?php echo $pass ? 'green': 'orange'; ?>"><?php echo $pass ? __('OK') : __('Low'); ?> (recommended: <?php echo strval($phpSetting['recommended']) . ($phpSetting['unit'] ? ' ' . $phpSetting['unit'] : '') . ')'; ?></span><br>
<?php
endforeach;
?>

View File

@ -201,7 +201,7 @@
if ($canEdit) {
echo $this->element('genericElements/assetLoader', array(
'js' => array(
'moment-with-locales',
'moment.min',
'codemirror/codemirror',
'codemirror/modes/markdown',
'codemirror/addons/simplescrollbars',
@ -221,4 +221,4 @@
if (!empty($additionalMarkdownElements)) {
echo $this->element($additionalMarkdownElements['path'], $additionalMarkdownElements['variables']);
}
?>

View File

@ -101,6 +101,7 @@ foreach($tabs as $tabName => $column):
echo $this->Form->create('Galaxy', array('url' => $url, 'style' => 'margin:0px;'));
echo $this->Form->input('target_ids', array('type' => 'text'));
echo $this->Form->input('attribute_ids', array('style' => 'display:none;', 'label' => false));
echo $this->Form->end();
?>
</div>

View File

@ -27,7 +27,7 @@
</div>
<?php
echo $this->Html->script('moment-with-locales');
echo $this->Html->script('moment.min');
echo $this->Html->script('event-timeline');
echo $this->Html->css('event-timeline');
?>

View File

@ -19,7 +19,10 @@
h($distributionLevels[$report['EventReport']['distribution']])
);
$table_data[] = array('key' => __('Last update'), 'value' => date('Y-m-d H:i:s', $report['EventReport']['timestamp']));
$table_data[] = array(
'key' => __('Last update'),
'html' => $this->Time->time($report['EventReport']['timestamp']),
);
if ($report['EventReport']['deleted']) {
$table_data[] = array(
'key' => __('Deleted'),

View File

@ -1,2 +0,0 @@
<?php
echo json_encode($result);

View File

@ -54,6 +54,7 @@
}
$attributes_count = isset($event['Attribute']) ? count($event['Attribute']) : 0;
$objects_count = isset($event['Object']) ? count($event['Object']) : 0;
$report_count = isset($event['EventReport']) ? count($event['EventReport']) : 0;
if (!empty($event['Object'])) {
foreach ($event['Object'] as $object) {
if (!empty($object['Attribute'])) {
@ -77,11 +78,60 @@
);
}
$table_data[] = array('key' => __('#Resolved Attributes'), 'value' => $count);
$table_data[] = array('key' => __('#Resolved Reports'), 'value' => $report_count);
echo $this->element('genericElements/viewMetaTable', array('table_data' => $table_data));
}
$attributeFields = array('category', 'type', 'value', 'uuid');
$header_present = false;
$typesWithData = array('attachment', 'malware-sample');
?>
<?php if (!empty($event['EventReport'])): ?>
<table class="table table-striped table-condensed">
<thead>
<tr>
<th><?= __('Import') ?></th>
<th><?= __('Name') ?></th>
<th class="hidden"><?php echo __('UUID');?></th>
<th><?= __('Content') ?></th>
<th><?= __('Distribution') ?></th>
</tr>
</thead>
<tbody>
<?php foreach($event['EventReport'] as $report): ?>
<tr class="MISPEventReport">
<td class="short" style="width:40px;text-align:center;">
<input type="checkbox" class="ImportMISPEventReport" checked />
</td>
<td class="EventReportName"><?= h($report['name']); ?></td>
<td class="EventReportUUID hidden"><?= h($report['uuid']); ?></td>
<td class="EventReportContent ellipsis-overflow" style="max-width:800px;">
<?= h($report['content']); ?>
</td>
<td class="short" style="width:40px;text-align:center;">
<select class='EventReportDistribution' style='padding:0px;height:20px;margin-bottom:0px;'>
<?php
foreach ($distributions as $distKey => $distValue) {
echo '<option value="' . h($distKey) . '" ' . ($distKey == $report['distribution'] ? 'selected="selected"' : '') . '>' . h($distValue) . '</option>';
}
?>
</select>
<div style="display:none;">
<select class='EventReportSharingGroup' style='padding:0px;height:20px;margin-top:3px;margin-bottom:0px;'>
<?php
foreach ($sgs as $sgKey => $sgValue) {
echo '<option value="' . h($sgKey) . '" ' . ($sgKey == $report['sharing_group_id'] ? 'selected="selected"' : '') . '>' . h($sgValue) . '</option>';
}
?>
</select>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
<table>
<?php endif; ?>
<?php
if (!empty($event['Object'])) {
?>
<table class="table table-striped table-condensed">
@ -389,7 +439,7 @@
</div>
<script type="text/javascript">
$(function() {
$('.AttributeDistribution, .ObjectDistribution').change(function() {
$('.AttributeDistribution, .ObjectDistribution, .EventReportDistribution').change(function() {
if ($(this).val() == 4) {
$(this).next().show();
} else {

View File

@ -5,7 +5,7 @@
echo $this->element('/genericElements/SideMenu/side_menu', array('menuList' => 'event', 'menuItem' => 'viewEvent', 'mayModify' => $mayModify, 'mayPublish' => $mayPublish));
echo $this->Html->script('doT');
echo $this->Html->script('extendext');
echo $this->Html->script('moment-with-locales');
echo $this->Html->script('moment.min');
echo $this->Html->css('query-builder.default');
echo $this->Html->script('query-builder');
echo $this->Html->css('attack_matrix');
@ -172,11 +172,11 @@
);
$table_data[] = array(
'key' => __('First recorded change'),
'value' => (!$oldest_timestamp) ? '' : date('Y-m-d H:i:s', $oldest_timestamp)
'html' => !$oldest_timestamp ? '' : $this->Time->time($oldest_timestamp),
);
$table_data[] = array(
'key' => __('Last change'),
'value' => date('Y-m-d H:i:s', $event['Event']['timestamp'])
'html' => $this->Time->time($event['Event']['timestamp']),
);
$table_data[] = array(
'key' => __('Modification map'),
@ -477,33 +477,33 @@
</div>
</div>
<br />
<div class="toggleButtons">
<button class="btn btn-inverse toggle-left btn.active qet galaxy-toggle-button" id="pivots_toggle" data-toggle-type="pivots">
<span class="icon-minus icon-white" title="<?php echo __('Toggle pivot graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle pivot graph');?>" style="vertical-align:top;"></span><?php echo __('Pivots');?>
<div id="eventToggleButtons">
<button class="btn btn-inverse toggle-left qet" id="pivots_toggle" data-toggle-type="pivots">
<span class="fas fa-minus" title="<?php echo __('Toggle pivot graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle pivot graph');?>"></span><?php echo __('Pivots');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="galaxies_toggle" data-toggle-type="galaxies">
<span class="icon-minus icon-white" title="<?php echo __('Toggle galaxies');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle galaxies');?>" style="vertical-align:top;"></span><?php echo __('Galaxy');?>
<button class="btn btn-inverse toggle qet" id="galaxies_toggle" data-toggle-type="galaxies">
<span class="fas fa-minus" title="<?php echo __('Toggle galaxies');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle galaxies');?>"></span><?php echo __('Galaxy');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="eventgraph_toggle" data-toggle-type="eventgraph" onclick="enable_interactive_graph();">
<span class="icon-plus icon-white" title="<?php echo __('Toggle Event graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event graph');?>" style="vertical-align:top;"></span><?php echo __('Event graph');?>
<button class="btn btn-inverse toggle qet" id="eventgraph_toggle" data-toggle-type="eventgraph" onclick="enable_interactive_graph();">
<span class="fas fa-plus" title="<?php echo __('Toggle Event graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event graph');?>"></span><?php echo __('Event graph');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="eventtimeline_toggle" data-toggle-type="eventtimeline" onclick="enable_timeline();">
<span class="icon-plus icon-white" title="<?php echo __('Toggle Event timeline');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event timeline');?>" style="vertical-align:top;"></span><?php echo __('Event timeline');?>
<button class="btn btn-inverse toggle qet" id="eventtimeline_toggle" data-toggle-type="eventtimeline" onclick="enable_timeline();">
<span class="fas fa-plus" title="<?php echo __('Toggle Event timeline');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Event timeline');?>"></span><?php echo __('Event timeline');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="correlationgraph_toggle" data-toggle-type="correlationgraph" data-load-url="<?= $baseurl ?>/events/viewGraph/<?= h($event['Event']['id']) ?>">
<span class="icon-plus icon-white" title="<?php echo __('Toggle Correlation graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Correlation graph');?>" style="vertical-align:top;"></span><?php echo __('Correlation graph');?>
<button class="btn btn-inverse toggle qet" id="correlationgraph_toggle" data-toggle-type="correlationgraph" data-load-url="<?= $baseurl ?>/events/viewGraph/<?= h($event['Event']['id']) ?>">
<span class="fas fa-plus" title="<?php echo __('Toggle Correlation graph');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle Correlation graph');?>"></span><?php echo __('Correlation graph');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="attackmatrix_toggle" data-toggle-type="attackmatrix" data-load-url="<?= $baseurl; ?>/events/viewGalaxyMatrix/<?= h($event['Event']['id']) ?>/mitre-attack/event/1">
<span class="icon-plus icon-white" title="<?php echo __('Toggle ATT&CK matrix');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle ATT&CK matrix');?>" style="vertical-align:top;"></span><?php echo __('ATT&CK matrix');?>
<button class="btn btn-inverse toggle qet" id="attackmatrix_toggle" data-toggle-type="attackmatrix" data-load-url="<?= $baseurl; ?>/events/viewGalaxyMatrix/<?= h($event['Event']['id']) ?>/mitre-attack/event/1">
<span class="fas fa-plus" title="<?php echo __('Toggle ATT&CK matrix');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle ATT&CK matrix');?>"></span><?php echo __('ATT&CK matrix');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="eventreport_toggle" data-toggle-type="eventreport">
<span class="icon-plus icon-white" title="<?php echo __('Toggle reports');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle reports');?>" style="vertical-align:top;"></span><?php echo __('Event reports');?>
<button class="btn btn-inverse toggle qet" id="eventreport_toggle" data-toggle-type="eventreport">
<span class="fas fa-plus" title="<?php echo __('Toggle reports');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle reports');?>"></span><?php echo __('Event reports');?>
</button>
<button class="btn btn-inverse toggle qet galaxy-toggle-button" id="attributes_toggle" data-toggle-type="attributes">
<span class="icon-minus icon-white" title="<?php echo __('Toggle attributes');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle attributes');?>" style="vertical-align:top;"></span><?php echo __('Attributes');?>
<button class="btn btn-inverse toggle qet" id="attributes_toggle" data-toggle-type="attributes">
<span class="fas fa-minus" title="<?php echo __('Toggle attributes');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle attributes');?>"></span><?php echo __('Attributes');?>
</button>
<button class="btn btn-inverse toggle-right qet galaxy-toggle-button" id="discussions_toggle" data-toggle-type="discussions">
<span class="icon-minus icon-white" title="<?php echo __('Toggle discussions');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle discussions');?>" style="vertical-align:top;"></span><?php echo __('Discussion');?>
<button class="btn btn-inverse toggle-right qet" id="discussions_toggle" data-toggle-type="discussions">
<span class="fas fa-minus" title="<?php echo __('Toggle discussions');?>" role="button" tabindex="0" aria-label="<?php echo __('Toggle discussions');?>"></span><?php echo __('Discussion');?>
</button>
</div>
<br />

View File

@ -191,7 +191,8 @@
'name' => __('Tag'),
'class' => 'short',
'data_path' => 'Tag',
'element' => 'tags'
'element' => 'tags',
'scope' => 'feeds'
),
array(
'name' => __('Visible'),

View File

@ -96,8 +96,8 @@
<div class="row-fuild">
<div id="relations_container"></div>
</div>
<div class="row-fluid">
<div id="elements_div" class="span8"></div>
<div class="">
<div id="elements_div"></div>
</div>
</div>
<script type="text/javascript">

View File

@ -6,9 +6,8 @@
'fields' => array(
array(
'name' => __('Id'),
'sort' => 'id',
'class' => 'short',
'data_path' => 'GalaxyClusterRelation.id',
'data_path' => 'id',
),
array(
'name' => __('Default'),
@ -18,23 +17,21 @@
),
array(
'name' => __('Galaxy Cluster Target (galaxy :: cluster)'),
'sort' => 'TargetCluster.tag_name',
'element' => 'galaxy_cluster_link',
'data_path' => 'TargetCluster',
'data_path_relation' => 'GalaxyClusterRelation',
'url_params_data_paths' => 'TargetCluster.id',
'data_path' => 'GalaxyCluster',
'data_path_relation' => '',
'url_params_data_paths' => 'GalaxyCluster.id',
'url' => $baseurl . '/galaxy_clusters/view'
),
array(
'name' => __('Relationship Type'),
'sort' => 'type',
'class' => 'short',
'data_path' => 'GalaxyClusterRelation.referenced_galaxy_cluster_type',
'data_path' => 'referenced_galaxy_cluster_type',
),
array(
'name' => __('Relationship Tag'),
'class' => 'short',
'data_path' => 'GalaxyClusterRelationTag.{n}.Tag',
'data_path' => 'Tag',
'element' => 'tags',
'elementParams' => array(
'searchScope' => 'taxonomy'
@ -43,18 +40,16 @@
),
array(
'name' => __('Distribution'),
'sort' => 'distribution',
'data_path' => 'GalaxyClusterRelation.distribution',
'data_path' => 'distribution',
'element' => 'distribution_levels',
),
),
'title' => __('Galaxy Cluster Relationships'),
'actions' => array(
array(
'title' => 'Edit',
'url' => '/galaxy_cluster_relations/edit',
'url_params_data_paths' => array(
'GalaxyClusterRelation.id'
'id'
),
'icon' => 'edit',
'complex_requirement' => array(
@ -71,7 +66,7 @@
'title' => 'Delete',
'url' => '/galaxy_cluster_relations/delete',
'url_params_data_paths' => array(
'GalaxyClusterRelation.id'
'id'
),
'postLink' => true,
'postLinkConfirm' => __('Are you sure you want to delete the Relationship?'),

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