Christophe Vandeplas 2024-04-29 15:32:45 +00:00 committed by GitHub
commit b1e68b7d1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 1606 additions and 148 deletions

3
.gitmodules vendored
View File

@ -10,3 +10,6 @@
[submodule "libraries/misp-taxonomies"] [submodule "libraries/misp-taxonomies"]
path = libraries/misp-taxonomies path = libraries/misp-taxonomies
url = https://github.com/MISP/misp-taxonomies url = https://github.com/MISP/misp-taxonomies
[submodule "libraries/misp-warninglists"]
path = libraries/misp-warninglists
url = https://github.com/MISP/misp-warninglists

@ -0,0 +1 @@
Subproject commit 2c7d29985ef77b568c0cfe3f035414db61f8b74c

View File

@ -3,6 +3,10 @@ parameters:
fileExtensions: fileExtensions:
- php - php
- ctp - ctp
paths:
- src
- tests
- templates
ignoreErrors: ignoreErrors:
- message: '#Undefined variable: \$this#' - message: '#Undefined variable: \$this#'
path: %currentWorkingDirectory%/templates path: %currentWorkingDirectory%/templates

View File

@ -279,6 +279,20 @@ class ACLComponent extends Component
'view' => ['*'], 'view' => ['*'],
'preview_entries' => ['*'] 'preview_entries' => ['*']
], ],
'Warninglists' => [
'checkValue' => ['*'],
'delete' => ['perm_warninglist'],
'enableWarninglist' => ['perm_warninglist'],
'getToggleField' => ['perm_warninglist'],
'index' => ['*'],
'toggleEnable' => ['perm_warninglist'],
'update' => [], // TODO shouldn't perm_warninglist be allowed to update?
'view' => ['*'],
'edit' => ['perm_warninglist'],
'add' => ['perm_warninglist'],
'export' => ['*'],
'import' => ['perm_warninglist'],
],
'ObjectTemplates' => [ 'ObjectTemplates' => [
'activate' => [], 'activate' => [],
'add' => ['perm_object_template'], 'add' => ['perm_object_template'],

View File

@ -3,14 +3,18 @@ namespace App\Controller\Component\Navigation;
class NoticelistsNavigation extends BaseNavigation class NoticelistsNavigation extends BaseNavigation
{ {
function addRoutes() public function addRoutes()
{ {
$this->bcf->addRoute('Noticelists', 'update', [ $this->bcf->addRoute(
'label' => __('Update Noticelists'), 'Noticelists',
'url' => '/noticelists/update', 'update',
'icon' => 'circle-up', [
'isPOST' => true, 'label' => __('Update Noticelists'),
]); 'url' => '/noticelists/update',
'icon' => 'circle-up',
'isPOST' => true,
]
);
} }
public function addActions() public function addActions()

View File

@ -50,11 +50,6 @@ class OrganisationsController extends AppController
'contextFilters' => [ 'contextFilters' => [
'custom' => $customContextFilters, 'custom' => $customContextFilters,
], ],
'afterFind' => function ($entity) {
$entity->setVirtual(['user_count']);
return $entity;
},
'contain' => $this->containFields, 'contain' => $this->containFields,
'statisticsFields' => $this->statisticsFields, 'statisticsFields' => $this->statisticsFields,
] ]

View File

@ -0,0 +1,501 @@
<?php
declare(strict_types=1);
namespace App\Controller;
class WarninglistsController extends AppController
{
public $paginate = [
'limit' => 60,
'maxLimit' => 9999,
'contain' => ['WarninglistTypes'],
'order' => [
'Warninglist.id' => 'DESC',
],
];
/**
* index page for warninglists
*
* @return \Cake\Http\Response|null|void Renders view
*/
public function index()
{
$params = [
'filters' => ['name', 'description', 'type'],
'quickFilters' => ['name'],
];
$this->CRUD->index($params);
$responsePayload = $this->CRUD->getResponsePayload();
if (!empty($responsePayload)) {
return $responsePayload;
}
// $filters = $this->harvestParameters(['value', 'enabled']);
// if (!empty($filters['value'])) {
// $this->paginate['conditions'] = [
// 'OR' => [
// 'LOWER(Warninglist.name) LIKE' => '%' . strtolower($filters['value']) . '%',
// 'LOWER(Warninglist.description) LIKE' => '%' . strtolower($filters['value']) . '%',
// 'LOWER(Warninglist.type)' => strtolower($filters['value']),
// ]
// ];
// }
// if (isset($filters['enabled'])) {
// $this->paginate['conditions'][] = ['Warninglist.enabled' => $filters['enabled']];
// }
// if ($this->ParamHandler->isRest()) {
// unset($this->paginate['limit']);
// $warninglists = $this->Warninglist->find('all', $this->paginate);
// } else {
// $warninglists = $this->paginate();
// }
// foreach ($warninglists as &$warninglist) {
// $validAttributes = array_column($warninglist['WarninglistType'], 'type');
// $warninglist['Warninglist']['valid_attributes'] = implode(', ', $validAttributes);
// unset($warninglist['WarninglistType']);
// }
// if ($this->ParamHandler->isRest()) {
// return $this->RestResponse->viewData(['Warninglists' => $warninglists], $this->response->getType());
// }
// $this->set('warninglists', $warninglists);
// $this->set('passedArgsArray', $filters);
$this->set('possibleCategories', $this->Warninglists->categories());
}
// public function update()
// {
// if (!$this->request->is('post')) {
// throw new MethodNotAllowedException(__('This action is only accessible via POST requests.'));
// }
// $result = $this->Warninglist->update();
// $this->Log = ClassRegistry::init('Log');
// $fails = 0;
// $successes = 0;
// if (!empty($result)) {
// if (isset($result['success'])) {
// foreach ($result['success'] as $id => $success) {
// if (isset($success['old'])) {
// $change = $success['name'] . ': updated from v' . $success['old'] . ' to v' . $success['new'];
// } else {
// $change = $success['name'] . ' v' . $success['new'] . ' installed';
// }
// $this->Log->create();
// $this->Log->saveOrFailSilently(array(
// 'org' => $this->Auth->user('Organisation')['name'],
// 'model' => 'Warninglist',
// 'model_id' => $id,
// 'email' => $this->Auth->user('email'),
// 'action' => 'update',
// 'user_id' => $this->Auth->user('id'),
// 'title' => __('Warning list updated'),
// 'change' => $change,
// ));
// $successes++;
// }
// }
// if (isset($result['fails'])) {
// foreach ($result['fails'] as $id => $fail) {
// $this->Log->create();
// $this->Log->saveOrFailSilently(array(
// 'org' => $this->Auth->user('Organisation')['name'],
// 'model' => 'Warninglist',
// 'model_id' => $id,
// 'email' => $this->Auth->user('email'),
// 'action' => 'update',
// 'user_id' => $this->Auth->user('id'),
// 'title' => __('Warning list failed to update'),
// 'change' => __('%s could not be installed/updated. Error: %s', $fail['name'], $fail['fail']), // TODO: needs to be optimized for non-SVO languages
// ));
// $fails++;
// }
// }
// } else {
// $this->Log->create();
// $this->Log->saveOrFailSilently(array(
// 'org' => $this->Auth->user('Organisation')['name'],
// 'model' => 'Warninglist',
// 'model_id' => 0,
// 'email' => $this->Auth->user('email'),
// 'action' => 'update',
// 'user_id' => $this->Auth->user('id'),
// 'title' => __('Warninglist update (nothing to update)'),
// 'change' => __('Executed an update of the warning lists, but there was nothing to update.'),
// ));
// }
// if ($successes == 0 && $fails == 0) {
// $flashType = 'info';
// $message = __('All warninglists are up to date already.');
// } elseif ($successes == 0) {
// $flashType = 'error';
// $message = __('Could not update any of the warning lists');
// } else {
// $flashType = 'success';
// $message = __('Successfully updated %s warninglists.', $successes);
// if ($fails != 0) {
// $message .= __(' However, could not update %s warninglists.', $fails); // TODO: non-SVO languages need to be considered
// }
// }
// if ($this->_isRest()) {
// return $this->RestResponse->saveSuccessResponse('Warninglist', 'update', false, $this->response->type(), $message);
// } else {
// $this->Flash->{$flashType}($message);
// $this->redirect(array('controller' => 'warninglists', 'action' => 'index'));
// }
// }
// public function add()
// {
// $types = array_combine($this->Warninglist->validate['type']['rule'][1], $this->Warninglist->validate['type']['rule'][1]);
// $this->set('possibleTypes', $types);
// $this->set('possibleCategories', $this->Warninglist->categories());
// $this->loadModel('Attribute');
// $this->set('matchingAttributes', array_combine(array_keys($this->Attribute->typeDefinitions), array_keys($this->Attribute->typeDefinitions)));
// $this->CRUD->add([
// 'beforeSave' => function (array $warninglist) {
// if (isset($warninglist['Warninglist']['entries'])) {
// $entries = $this->Warninglist->parseFreetext($warninglist['Warninglist']['entries']);
// unset($warninglist['Warninglist']['entries']);
// $warninglist['WarninglistEntry'] = $entries;
// }
// if (empty($warninglist['WarninglistEntry'])) {
// $warninglist['Warninglist']['entries'] = ''; // Make model validation fails
// }
// if (empty($warninglist['Warninglist']['matching_attributes'])) {
// $warninglist['Warninglist']['matching_attributes'] = ['ALL'];
// }
// if (isset($warninglist['Warninglist']['matching_attributes']) && is_array($warninglist['Warninglist']['matching_attributes'])) {
// $warninglist['WarninglistType'] = [];
// foreach ($warninglist['Warninglist']['matching_attributes'] as $attribute) {
// $warninglist['WarninglistType'][] = ['type' => $attribute];
// }
// }
// $warninglist['Warninglist']['default'] = 0;
// return $warninglist;
// },
// ]);
// if ($this->restResponsePayload) {
// return $this->restResponsePayload;
// }
// }
// public function edit($id = null)
// {
// $types = array_combine($this->Warninglist->validate['type']['rule'][1], $this->Warninglist->validate['type']['rule'][1]);
// $this->set('possibleTypes', $types);
// $this->set('possibleCategories', $this->Warninglist->categories());
// $this->loadModel('Attribute');
// $this->set('matchingAttributes', array_combine(array_keys($this->Attribute->typeDefinitions), array_keys($this->Attribute->typeDefinitions)));
// $this->CRUD->edit($id, [
// 'conditions' => ['default' => 0], // it is not possible to edit default warninglist
// 'contain' => ['WarninglistEntry', 'WarninglistType'],
// 'fields' => ['name', 'description', 'type', 'category', 'entries', 'matching_attributes'],
// 'redirect' => ['action' => 'view', $id],
// 'beforeSave' => function (array $warninglist) {
// if (isset($warninglist['Warninglist']['entries'])) {
// $entries = $this->Warninglist->parseFreetext($warninglist['Warninglist']['entries']);
// unset($warninglist['Warninglist']['entries']);
// $warninglist['WarninglistEntry'] = $entries;
// }
// if (empty($warninglist['WarninglistEntry'])) {
// $warninglist['Warninglist']['entries'] = ''; // Make model validation fails
// }
// if (isset($warninglist['Warninglist']['matching_attributes']) && is_array($warninglist['Warninglist']['matching_attributes'])) {
// $warninglist['WarninglistType'] = [];
// foreach ($warninglist['Warninglist']['matching_attributes'] as $attribute) {
// $warninglist['WarninglistType'][] = ['type' => $attribute];
// }
// }
// $warninglist['Warninglist']['version']++;
// return $warninglist;
// },
// ]);
// if ($this->restResponsePayload) {
// return $this->restResponsePayload;
// }
// if (isset($this->request->data['WarninglistEntry'])) {
// $entries = [];
// foreach ($this->request->data['WarninglistEntry'] as $entry) {
// $value = $entry['value'];
// if ($entry['comment']) {
// $value .= ' # ' . $entry['comment'];
// }
// $entries[] = $value;
// }
// $this->request->data['Warninglist']['entries'] = implode("\n", $entries);
// }
// if (isset($this->request->data['WarninglistType'])) {
// $attributes = array_column($this->request->data['WarninglistType'], 'type');
// $this->request->data['Warninglist']['matching_attributes'] = $attributes;
// }
// $this->render('add');
// }
// /*
// * toggle warninglists on or offset
// * Simply POST an ID or a list of IDs to toggle the current state
// * To control what state the warninglists should have after execution instead of just blindly toggling them, simply pass the enabled flag
// * Example:
// * {"id": [5, 8], "enabled": 1}
// * Alternatively search by a substring in the warninglist's named, such as:
// * {"name": ["%alexa%", "%iana%"], "enabled": 1}
// */
// public function toggleEnable()
// {
// if (!$this->request->is('post')) {
// return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('This function only accepts POST requests.'))), 'status' => 200, 'type' => 'json'));
// }
// if (isset($this->request->data['Warninglist']['data'])) {
// $id = $this->request->data['Warninglist']['data'];
// } else {
// if (!empty($this->request->data['id'])) {
// $id = $this->request->data['id'];
// } elseif (!empty($this->request->data['name'])) {
// if (!is_array($this->request->data['name'])) {
// $names = [$this->request->data['name']];
// } else {
// $names = $this->request->data['name'];
// }
// $conditions = array();
// foreach ($names as $name) {
// $conditions['OR'][] = ['LOWER(Warninglist.name] LIKE' => strtolower($name));
// }
// $id = $this->Warninglist->find('column', array(
// 'conditions' => $conditions,
// 'fields' => ['Warninglist.id']
// ));
// }
// }
// if (isset($this->request->data['enabled'])) {
// $enabled = $this->request->data['enabled'];
// }
// if (empty($id)) {
// return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Warninglist not found.'))), 'status' => 200, 'type' => 'json'));
// }
// $currentState = $this->Warninglist->find('all', ['conditions' => ['id' => $id], 'recursive' => -1]);
// if (empty($currentState)) {
// return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Warninglist(s) not found.'))), 'status' => 200, 'type' => 'json'));
// }
// $success = 0;
// foreach ($currentState as $warningList) {
// if (isset($enabled)) {
// $warningList['Warninglist']['enabled'] = $enabled;
// $message = $enabled ? 'enabled' : 'disabled';
// } else {
// if ($warningList['Warninglist']['enabled']) {
// $warningList['Warninglist']['enabled'] = 0;
// $message = 'disabled';
// } else {
// $warningList['Warninglist']['enabled'] = 1;
// $message = 'enabled';
// }
// if (!isset($enabled) && count($currentState) > 1) {
// $message = 'toggled';
// }
// }
// if ($this->Warninglist->save($warningList)) {
// $success += 1;
// }
// $this->Warninglist->regenerateWarninglistCaches($warningList['Warninglist']['id']);
// }
// if ($success) {
// return new CakeResponse(array('body'=> json_encode(array('saved' => true, 'success' => $success . __(' warninglist(s) ') . $message)), 'status' => 200, 'type' => 'json')); // TODO: non-SVO lang considerations
// } else {
// return new CakeResponse(array('body'=> json_encode(array('saved' => false, 'errors' => __('Warninglist(s) could not be toggled.'))), 'status' => 200, 'type' => 'json'));
// }
// }
// public function enableWarninglist($id, $enable = false)
// {
// $this->Warninglist->id = $id;
// if (!$this->Warninglist->exists()) {
// throw new NotFoundException(__('Invalid Warninglist.'));
// }
// // DBMS interoperability: convert boolean false to integer 0 so cakephp doesn't try to insert an empty string into the database
// if ($enable === false) {
// $enable = 0;
// }
// $this->Warninglist->saveField('enabled', $enable);
// $this->Warninglist->regenerateWarninglistCaches($id);
// if ($enable === 0) {
// $this->Flash->success(__('Warninglist disabled'));
// }
// else {
// $this->Flash->success(__('Warninglist enabled'));
// }
// $this->redirect(array('controller' => 'warninglists', 'action' => 'view', $id));
// }
// public function getToggleField()
// {
// if (!$this->request->is('ajax')) {
// throw new MethodNotAllowedException(__('This action is available via AJAX only.'));
// }
// $this->layout = false;
// $this->render('ajax/getToggleField');
// }
// public function view($id)
// {
// if (!is_numeric($id)) {
// throw new NotFoundException(__('Invalid ID.'));
// }
// $warninglist = $this->Warninglist->find('first', array(
// 'contain' => ['WarninglistEntry', 'WarninglistType'],
// 'conditions' => ['id' => $id])
// );
// if (empty($warninglist)) {
// throw new NotFoundException(__('Warninglist not found.'));
// }
// if ($this->IndexFilter->isCsv()) {
// $csv = [];
// foreach ($warninglist['WarninglistEntry'] as $entry) {
// $line = $entry['value'];
// if ($entry['comment']) {
// $line .= ';' . $entry['comment'];
// }
// $csv[] = $line;
// }
// return $this->RestResponse->viewData(implode("\n", $csv), 'csv');
// }
// if ($this->_isRest()) {
// $warninglist['Warninglist']['WarninglistEntry'] = $warninglist['WarninglistEntry'];
// $warninglist['Warninglist']['WarninglistType'] = $warninglist['WarninglistType'];
// return $this->RestResponse->viewData(['Warninglist' => $warninglist['Warninglist']], $this->response->type());
// }
// $this->set('warninglist', $warninglist);
// $this->set('possibleCategories', $this->Warninglist->categories());
// }
// public function import()
// {
// $this->request->allowMethod(['post']);
// if (empty($this->request->data)) {
// throw new BadRequestException(__('No valid data received.'));
// }
// foreach (['name', 'type', 'version', 'description', 'matching_attributes', 'list'] as $filed) {
// if (!isset($this->request->data[$filed])) {
// throw new BadRequestException(__('No valid data received: field `%s` is missing.', $filed));
// }
// }
// if (!is_array($this->request->data['list'])) {
// throw new BadRequestException(__('No valid data received: `list` field is not array'));
// }
// try {
// $id = $this->Warninglist->import($this->request->data);
// return $this->RestResponse->saveSuccessResponse('Warninglist', 'import', $id, false, __('Warninglist imported'));
// } catch (Exception $e) {
// return $this->RestResponse->saveFailResponse('Warninglist', 'import', false, $e->getMessage());
// }
// }
// public function export($id = null)
// {
// if (empty($id)) {
// throw new NotFoundException(__('Warninglist not found.'));
// }
// $warninglist = $this->Warninglist->find('first', [
// 'contain' => ['WarninglistType'],
// 'conditions' => ['id' => $id],
// ]);
// if (empty($warninglist)) {
// throw new NotFoundException(__('Warninglist not found.'));
// }
// $matchingAttributes = array_column($warninglist['WarninglistType'], 'type');
// $list = $this->Warninglist->WarninglistEntry->find('column', [
// 'conditions' => ['warninglist_id' => $warninglist['Warninglist']['id']],
// 'fields' => ['value'],
// ]);
// $output = [
// 'name' => $warninglist['Warninglist']['name'],
// 'type' => $warninglist['Warninglist']['type'],
// 'version' => $warninglist['Warninglist']['version'],
// 'description' => $warninglist['Warninglist']['description'],
// 'matching_attributes' => $matchingAttributes,
// 'list' => $list,
// ];
// return $this->RestResponse->viewData($output, 'json');
// }
// public function delete($id)
// {
// if ($this->request->is('post')) {
// $id = (int)$id;
// $result = $this->Warninglist->quickDelete($id);
// if ($result) {
// $this->Flash->success(__('Warninglist successfully deleted.'));
// } else {
// $this->Flash->error(__('Warninglist could not be deleted.'));
// }
// $this->redirect(['controller' => 'warninglists', 'action' => 'index']);
// } else {
// if ($this->request->is('ajax')) {
// $this->set('id', $id);
// $this->render('ajax/delete_confirmation');
// } else {
// throw new MethodNotAllowedException(__('This function can only be reached via AJAX.'));
// }
// }
// }
// public function checkValue()
// {
// if ($this->request->is('post')) {
// if (empty($this->request->data)) {
// throw new NotFoundException(__('No valid data received.'));
// }
// $data = $this->request->data;
// if (is_array($data) && isset($data['Warninglist'])) {
// $data = $data['Warninglist'];
// }
// if (!is_array($data)) {
// $data = [$data];
// }
// if (array_key_exists('[]', $data)) {
// $data = $data['[]'];
// }
// $hits = array();
// $warninglists = $this->Warninglist->getEnabled();
// foreach ($data as $dataPoint) {
// $dataPoint = trim($dataPoint);
// foreach ($warninglists as $warninglist) {
// $values = $this->Warninglist->getFilteredEntries($warninglist);
// $result = $this->Warninglist->checkValue($values, $dataPoint, '', $warninglist['Warninglist']['type']);
// if ($result !== false) {
// $hits[$dataPoint][] = [
// 'id' => $warninglist['Warninglist']['id'],
// 'name' => $warninglist['Warninglist']['name'],
// 'matched' => $result[0],
// ];
// }
// }
// }
// if ($this->_isRest()) {
// return $this->RestResponse->viewData($hits, $this->response->type());
// }
// $this->set('hits', $hits);
// $this->set('data', $data);
// } else {
// if ($this->_isRest()) {
// return $this->RestResponse->describe('Warninglists', 'checkValue', false, $this->response->type());
// }
// }
// }
}

View File

@ -1,13 +1,15 @@
<?php <?php
declare(strict_types=1);
namespace App\Model\Entity; namespace App\Model\Entity;
use Cake\Datasource\ConnectionManager;
use Cake\ORM\Entity; use Cake\ORM\Entity;
class AppModel extends Entity class AppModel extends Entity
{ {
const BROTLI_HEADER = "\xce\xb2\xcf\x81"; public const BROTLI_HEADER = "\xce\xb2\xcf\x81";
const BROTLI_MIN_LENGTH = 200; public const BROTLI_MIN_LENGTH = 200;
public const ACTION_ADD = 'add', public const ACTION_ADD = 'add',
ACTION_EDIT = 'edit', ACTION_EDIT = 'edit',
@ -22,12 +24,22 @@ class AppModel extends Entity
ACTION_LOGIN_FAIL = 'login_fail', ACTION_LOGIN_FAIL = 'login_fail',
ACTION_LOGOUT = 'logout'; ACTION_LOGOUT = 'logout';
/**
* getConstant
*
* @param mixed $name Name of the constant to get
* @return mixed the value of the constant
*/
public function getConstant($name) public function getConstant($name)
{ {
return constant('self::' . $name); return constant('self::' . $name);
} }
/**
* getAccessibleFieldForNew
*
* @return array
*/
public function getAccessibleFieldForNew(): array public function getAccessibleFieldForNew(): array
{ {
return $this->_accessibleOnNew ?? []; return $this->_accessibleOnNew ?? [];
@ -64,9 +76,10 @@ class AppModel extends Entity
$tag = [ $tag = [
'id' => $tag['id'], 'id' => $tag['id'],
'name' => $tag['name'], 'name' => $tag['name'],
'colour' => $tag['colour'] 'colour' => $tag['colour'],
]; ];
} }
return $tags; return $tags;
} }
@ -77,13 +90,13 @@ class AppModel extends Entity
$alignmentDataToKeep = [ $alignmentDataToKeep = [
'individual' => [ 'individual' => [
'id', 'id',
'email' 'email',
], ],
'organisation' => [ 'organisation' => [
'id', 'id',
'uuid', 'uuid',
'name' 'name',
] ],
]; ];
foreach ($alignments as $alignment) { foreach ($alignments as $alignment) {
foreach (array_keys($alignmentDataToKeep) as $type) { foreach (array_keys($alignmentDataToKeep) as $type) {
@ -97,6 +110,7 @@ class AppModel extends Entity
} }
} }
} }
return $rearrangedAlignments; return $rearrangedAlignments;
} }
@ -106,15 +120,35 @@ class AppModel extends Entity
$this->organisation = [ $this->organisation = [
'id' => $this->organisation['id'], 'id' => $this->organisation['id'],
'name' => $this->organisation['name'], 'name' => $this->organisation['name'],
'uuid' => $this->organisation['uuid'] 'uuid' => $this->organisation['uuid'],
]; ];
} }
if (in_array('individual', $typesToRearrange) && isset($this->individual)) { if (in_array('individual', $typesToRearrange) && isset($this->individual)) {
$this->individual = [ $this->individual = [
'id' => $this->individual['id'], 'id' => $this->individual['id'],
'email' => $this->individual['email'], 'email' => $this->individual['email'],
'uuid' => $this->individual['uuid'] 'uuid' => $this->individual['uuid'],
]; ];
} }
} }
/**
* @param string $field The field name to add
* @param \App\Model\Entity\AppModel $model The model to use
* @param array $conditions The conditions for the query
*/
public function addCountField($field, AppModel $model, array $conditions)
{
$dataSource = ConnectionManager::get('default')->config['datasource'];
$subQuery = $dataSource->buildStatement(
[
'fields' => ['COUNT(*)'],
'table' => $dataSource->fullTableName($model),
'alias' => $model->alias,
'conditions' => $conditions,
],
$model
);
$this->virtualFields[$field] = $subQuery;
}
} }

View File

@ -1,16 +1,31 @@
<?php <?php
declare(strict_types=1);
namespace App\Model\Entity; namespace App\Model\Entity;
use App\Model\Entity\AppModel; use Cake\ORM\TableRegistry;
use Cake\ORM\Entity;
class Warninglist extends AppModel class Warninglist extends AppModel
{ {
public const CATEGORY_FALSE_POSITIVE = 'false_positive', public const CATEGORY_FALSE_POSITIVE = 'false_positive',
CATEGORY_KNOWN = 'known'; CATEGORY_KNOWN = 'known';
public const TLDS = array( public const TLDS = [
'TLDs as known by IANA' 'TLDs as known by IANA',
); ];
/**
* _getWarninglistEntryCount adds virtual field counting the number of entries in the warninglist
*
* @return int the amount of entries in the warninglist
*/
protected function _getWarninglistEntryCount()
{
$warninglist_entries_table = TableRegistry::getTableLocator()->get('WarninglistEntries');
$entry_count = $warninglist_entries_table->find('all')
->where(['warninglist_id' => $this->id])
->count();
return $entry_count;
}
} }

View File

@ -1,10 +1,8 @@
<?php <?php
declare(strict_types=1);
namespace App\Model\Entity; namespace App\Model\Entity;
use App\Model\Entity\AppModel;
use Cake\ORM\Entity;
class WarninglistEntry extends AppModel class WarninglistEntry extends AppModel
{ {
public $virtualFields = []; public $virtualFields = [];

View File

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace App\Model\Entity;
class WarninglistType extends AppModel
{
public $virtualFields = [];
}

View File

@ -1,13 +1,18 @@
<?php <?php
declare(strict_types=1);
namespace App\Model\Table; namespace App\Model\Table;
use App\Model\Table\AppTable;
use Cake\ORM\Table;
use Cake\Validation\Validator; use Cake\Validation\Validator;
class WarninglistEntriesTable extends AppTable class WarninglistEntriesTable extends AppTable
{ {
/**
* initialize
*
* @param mixed $config Configuration
* @return void
*/
public function initialize(array $config): void public function initialize(array $config): void
{ {
parent::initialize($config); parent::initialize($config);
@ -16,17 +21,24 @@ class WarninglistEntriesTable extends AppTable
'Warninglist', 'Warninglist',
[ [
'dependent' => true, 'dependent' => true,
'propertyName' => 'Warninglist' 'propertyName' => 'Warninglist',
] ]
); );
$this->setDisplayField('value'); $this->setDisplayField('value');
} }
/**
* validationDefault
*
* @param mixed $validator Validator
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator): Validator public function validationDefault(Validator $validator): Validator
{ {
$validator $validator
->notEmptyString('value') ->notEmptyString('value')
->requirePresence(['value', 'warninglist_id'], 'create'); ->requirePresence(['value', 'warninglist_id'], 'create');
return $validator; return $validator;
} }
} }

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Model\Table;
use Cake\Validation\Validator;
class WarninglistTypesTable extends AppTable
{
/**
* initialize
*
* @param mixed $config Configuration
* @return void
*/
public function initialize(array $config): void
{
parent::initialize($config);
// $this->addBehavior('AuditLog');
$this->belongsTo(
'Warninglist',
[
'dependent' => true,
'propertyName' => 'Warninglist',
]
);
$this->setDisplayField('value');
}
/**
* validationDefault
*
* @param mixed $validator Validator
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator): Validator
{
$validator
->notEmptyString('type')
->requirePresence(['type', 'warninglist_id'], 'create');
return $validator;
}
}

View File

@ -1,54 +1,81 @@
<?php <?php
declare(strict_types=1);
namespace App\Model\Table; namespace App\Model\Table;
use App\Model\Table\AppTable; use App\Lib\Tools\CidrTool;
use Cake\Validation\Validator; use App\Lib\Tools\FileAccessTool;
use App\Lib\Tools\RedisTool;
use App\Model\Entity\Warninglist;
use Cake\Core\Configure; use Cake\Core\Configure;
use Cake\ORM\RulesChecker; use Cake\ORM\RulesChecker;
use App\Lib\Tools\CidrTool; use Cake\Validation\Validator;
use App\Lib\Tools\RedisTool;
use App\Lib\Tools\FileAccessTool;
use App\Model\Entity\Warninglist;
use Exception; use Exception;
class WarninglistsTable extends AppTable class WarninglistsTable extends AppTable
{ {
/**
/** @var array */ * @var array
*/
private $entriesCache = []; private $entriesCache = [];
/** @var array|null */ /**
* @var array|null
*/
private $enabledCache = null; private $enabledCache = null;
private $showForAll; private $showForAll;
/**
* initialize
*
* @param mixed $config the config
* @return void
*/
public function initialize(array $config): void public function initialize(array $config): void
{ {
parent::initialize($config);
$this->showForAll = Configure::read('MISP.warning_for_all'); $this->showForAll = Configure::read('MISP.warning_for_all');
$this->hasMany( $this->hasMany(
'WarninglistEntries', 'WarninglistEntries',
[ [
'dependent' => true, 'dependent' => true,
'propertyName' => 'WarninglistEntry' 'propertyName' => 'WarninglistEntry',
] ]
); );
$this->hasMany( $this->hasMany(
'WarninglistTypes', 'WarninglistTypes',
[ [
'dependent' => true, 'dependent' => true,
'propertyName' => 'WarninglistType' 'propertyName' => 'WarninglistType',
] ]
); );
parent::initialize($config);
$this->setTable('warninglists');
$this->setDisplayField('name');
$this->setPrimaryKey('id');
} }
/**
* buildRules
*
* @param \Cake\ORM\RulesChecker $rules the rules
* @return \Cake\ORM\RulesChecker
*/
public function buildRules(RulesChecker $rules): RulesChecker public function buildRules(RulesChecker $rules): RulesChecker
{ {
$rules->add($rules->isUnique(['name'])); $rules->add($rules->isUnique(['name']));
return $rules; return $rules;
} }
/**
* validationDefault
*
* @param \Cake\Validation\Validator $validator the validator
* @return \Cake\Validation\Validator
*/
public function validationDefault(Validator $validator): Validator public function validationDefault(Validator $validator): Validator
{ {
$validator $validator
@ -71,11 +98,12 @@ class WarninglistsTable extends AppTable
] ]
) )
->requirePresence(['name', 'description', 'entries'], 'create'); ->requirePresence(['name', 'description', 'entries'], 'create');
return $validator; return $validator;
} }
// TODO: [3.x-MIGRATION] re-implement this as a custom validation rule // TODO: [3.x-MIGRATION] re-implement this as a custom validation rule
// public function beforeValidate($options = array()) // public function beforeValidate($options = [])
// { // {
// if (isset($this->data['WarninglistEntry'])) { // if (isset($this->data['WarninglistEntry'])) {
// if ($this->data['Warninglist']['type'] === 'cidr') { // if ($this->data['Warninglist']['type'] === 'cidr') {
@ -103,7 +131,7 @@ class WarninglistsTable extends AppTable
/** /**
* Attach warninglist matches to attributes or proposals with IDS mark. * Attach warninglist matches to attributes or proposals with IDS mark.
* *
* @param array $attributes * @param array $attributes the attributes to attach to
* @return array Warninglist ID => name * @return array Warninglist ID => name
*/ */
public function attachWarninglistToAttributes(array &$attributes) public function attachWarninglistToAttributes(array &$attributes)
@ -133,6 +161,7 @@ class WarninglistsTable extends AppTable
if (!empty($eventWarnings)) { if (!empty($eventWarnings)) {
$this->assignComments($attributes); $this->assignComments($attributes);
} }
return $eventWarnings; return $eventWarnings;
} }
@ -218,7 +247,9 @@ class WarninglistsTable extends AppTable
/** /**
* Assign comments to warninglist hits. * Assign comments to warninglist hits.
* @param array $attributes *
* @param array $attributes the attributes to assign comments to
* @return void
*/ */
private function assignComments(array &$attributes) private function assignComments(array &$attributes)
{ {
@ -233,19 +264,24 @@ class WarninglistsTable extends AppTable
$conditions = []; $conditions = [];
foreach ($toFetch as $warninglistId => $values) { foreach ($toFetch as $warninglistId => $values) {
$conditions[] = ['AND' => [ $conditions[] = [
'warninglist_id' => $warninglistId, 'AND' => [
'value' => array_unique($values), 'warninglist_id' => $warninglistId,
]]; 'value' => array_unique($values),
]
];
} }
$entries = $this->WarninglistEntry->find('all', [ $entries = $this->WarninglistEntry->find(
'conditions' => [ 'all',
'OR' => $conditions, [
'comment !=' => '', 'conditions' => [
], 'OR' => $conditions,
'fields' => ['value', 'warninglist_id', 'comment'], 'comment !=' => '',
]); ],
'fields' => ['value', 'warninglist_id', 'comment'],
]
);
if (empty($entries)) { if (empty($entries)) {
return; return;
} }
@ -267,14 +303,22 @@ class WarninglistsTable extends AppTable
} }
} }
/**
* update the warninglists
*
* @return array the result of the update
*/
public function update() public function update()
{ {
// Fetch existing default warninglists // Fetch existing default warninglists
$existingWarninglist = $this->find('all', [ $existingWarninglist = $this->find(
'fields' => ['id', 'name', 'version', 'enabled'], 'all',
'recursive' => -1, [
'conditions' => ['default' => 1], 'fields' => ['id', 'name', 'version', 'enabled'],
])->toArray(); 'recursive' => -1,
'conditions' => ['default' => 1],
]
)->toArray();
$existingWarninglist = array_column(array_column($existingWarninglist, 'Warninglist'), null, 'name'); $existingWarninglist = array_column(array_column($existingWarninglist, 'Warninglist'), null, 'name');
$directories = glob(APP . '..' . DS . 'libraries' . DS . 'misp-warninglists' . DS . 'lists' . DS . '*', GLOB_ONLYDIR); $directories = glob(APP . '..' . DS . 'libraries' . DS . 'misp-warninglists' . DS . 'lists' . DS . '*', GLOB_ONLYDIR);
@ -306,40 +350,52 @@ class WarninglistsTable extends AppTable
if (!empty($result['success']) || !empty($result['fails'])) { if (!empty($result['success']) || !empty($result['fails'])) {
$this->regenerateWarninglistCaches(); $this->regenerateWarninglistCaches();
} }
return $result; return $result;
} }
/**
* quickDelete
*
* @param mixed $id the id of the list to delete
* @return array the result of the deletion
*/
public function quickDelete($id) public function quickDelete($id)
{ {
$result = $this->WarninglistEntry->deleteAll( $result = $this->WarninglistEntry->deleteAll(
array('WarninglistEntry.warninglist_id' => $id), ['WarninglistEntry.warninglist_id' => $id],
false false
); );
if ($result) { if ($result) {
$result = $this->WarninglistType->deleteAll( $result = $this->WarninglistType->deleteAll(
array('WarninglistType.warninglist_id' => $id), ['WarninglistType.warninglist_id' => $id],
false false
); );
} }
if ($result) { if ($result) {
$result = $this->delete($id, false); $result = $this->delete($id, false);
} }
return $result; return $result;
} }
/** /**
* Import single warninglist * Import single warninglist
* @param array $list *
* @param array $list a list to import
* @return int Warninglist ID * @return int Warninglist ID
* @throws Exception * @throws \Exception
*/ */
public function import(array $list) public function import(array $list)
{ {
$existingWarninglist = $this->find('first', [ $existingWarninglist = $this->find(
'fields' => ['id', 'name', 'version', 'enabled', 'default'], 'first',
'recursive' => -1, [
'conditions' => ['name' => $list['name']], 'fields' => ['id', 'name', 'version', 'enabled', 'default'],
]); 'recursive' => -1,
'conditions' => ['name' => $list['name']],
]
);
if ($existingWarninglist && $existingWarninglist['Warninglist']['default']) { if ($existingWarninglist && $existingWarninglist['Warninglist']['default']) {
throw new Exception('It is not possible to modify default warninglist.'); throw new Exception('It is not possible to modify default warninglist.');
@ -352,11 +408,11 @@ class WarninglistsTable extends AppTable
} }
/** /**
* @param array $list * @param array $list List to update
* @param array $existing * @param array $existing Existing list
* @param bool $default * @param bool $default Whether the list is default
* @return int Warninglist ID * @return int Warninglist ID
* @throws Exception * @throws \Exception
*/ */
private function __updateList(array $list, array $existing, $default = true) private function __updateList(array $list, array $existing, $default = true)
{ {
@ -371,7 +427,7 @@ class WarninglistsTable extends AppTable
$this->WarninglistEntry->deleteAll(['WarninglistEntry.warninglist_id' => $existing['id']], false); $this->WarninglistEntry->deleteAll(['WarninglistEntry.warninglist_id' => $existing['id']], false);
$this->WarninglistType->deleteAll(['WarninglistType.warninglist_id' => $existing['id']], false); $this->WarninglistType->deleteAll(['WarninglistType.warninglist_id' => $existing['id']], false);
} }
$fieldsToSave = array('name', 'version', 'description', 'type', 'enabled'); $fieldsToSave = ['name', 'version', 'description', 'type', 'enabled'];
foreach ($fieldsToSave as $fieldToSave) { foreach ($fieldsToSave as $fieldToSave) {
$warninglist['Warninglist'][$fieldToSave] = $list[$fieldToSave]; $warninglist['Warninglist'][$fieldToSave] = $list[$fieldToSave];
} }
@ -380,7 +436,7 @@ class WarninglistsTable extends AppTable
} }
$this->create(); $this->create();
if (!$this->save($warninglist)) { if (!$this->save($warninglist)) {
throw new Exception("Could not save warninglist because of validation errors: " . json_encode($this->validationErrors)); throw new Exception('Could not save warninglist because of validation errors: ' . json_encode($this->validationErrors));
} }
$db = $this->getDataSource(); $db = $this->getDataSource();
@ -418,7 +474,7 @@ class WarninglistsTable extends AppTable
} }
$values = []; $values = [];
foreach ($list['matching_attributes'] as $type) { foreach ($list['matching_attributes'] as $type) {
$values[] = array('type' => $type, 'warninglist_id' => $warninglistId); $values[] = ['type' => $type, 'warninglist_id' => $warninglistId];
} }
$this->WarninglistType->saveMany($values); $this->WarninglistType->saveMany($values);
@ -428,9 +484,10 @@ class WarninglistsTable extends AppTable
/** /**
* Regenerate the warninglist caches, but if an ID is passed along, only regen the entries for the given ID. * Regenerate the warninglist caches, but if an ID is passed along, only regen the entries for the given ID.
* This allows us to enable/disable a single warninglist without regenerating all caches. * This allows us to enable/disable a single warninglist without regenerating all caches.
* @param int|null $id *
* @param int|null $id the ID of the warninglist to regenerate
* @return bool * @return bool
* @throws RedisException * @throws \RedisException
*/ */
public function regenerateWarninglistCaches($id = null) public function regenerateWarninglistCaches($id = null)
{ {
@ -453,26 +510,34 @@ class WarninglistsTable extends AppTable
if ($id && $warninglist['Warninglist']['id'] != $id) { if ($id && $warninglist['Warninglist']['id'] != $id) {
continue; continue;
} }
$entries = $this->WarninglistEntry->find('column', array( $entries = $this->WarninglistEntry->find(
'conditions' => array('warninglist_id' => $warninglist['Warninglist']['id']), 'column',
'fields' => array('value') [
)); 'conditions' => ['warninglist_id' => $warninglist['Warninglist']['id']],
'fields' => ['value'],
]
);
$this->cacheWarninglistEntries($entries, $warninglist['Warninglist']['id']); $this->cacheWarninglistEntries($entries, $warninglist['Warninglist']['id']);
} }
return true; return true;
} }
/** /**
* Get enable warninglists and cache them. * Get enable warninglists and cache them.
* @return array *
* @return array the warning lists
*/ */
private function getEnabledAndCacheWarninglist() private function getEnabledAndCacheWarninglist()
{ {
$warninglists = $this->find('all', [ $warninglists = $this->find(
'contain' => ['WarninglistType'], 'all',
'conditions' => ['enabled' => 1], [
'fields' => ['id', 'name', 'type', 'category'], 'contain' => ['WarninglistType'],
]); 'conditions' => ['enabled' => 1],
'fields' => ['id', 'name', 'type', 'category'],
]
);
// Convert type to array // Convert type to array
foreach ($warninglists as &$warninglist) { foreach ($warninglists as &$warninglist) {
@ -491,6 +556,13 @@ class WarninglistsTable extends AppTable
return $warninglists; return $warninglists;
} }
/**
* cacheWarninglistEntries
*
* @param mixed $warninglistEntries the entries
* @param mixed $id the id of the warninglist
* @return bool true if the cache was successful
*/
private function cacheWarninglistEntries(array $warninglistEntries, $id) private function cacheWarninglistEntries(array $warninglistEntries, $id)
{ {
try { try {
@ -508,12 +580,13 @@ class WarninglistsTable extends AppTable
$redis->sAdd($key, $entry); $redis->sAdd($key, $entry);
} }
} }
return true; return true;
} }
/** /**
* @return array * @return array
* @throws JsonException * @throws \JsonException
*/ */
public function getEnabled() public function getEnabled()
{ {
@ -533,11 +606,14 @@ class WarninglistsTable extends AppTable
} }
$this->enabledCache = $warninglists; $this->enabledCache = $warninglists;
return $warninglists; return $warninglists;
} }
/** /**
* @param int $id * get warninglist entries (from cache if possible) and cache if needed
*
* @param int $id the ID of the warninglist
* @return array * @return array
*/ */
private function getWarninglistEntries($id) private function getWarninglistEntries($id)
@ -550,18 +626,22 @@ class WarninglistsTable extends AppTable
} catch (Exception $e) { } catch (Exception $e) {
} }
$entries = $this->WarninglistEntry->find('column', array( $entries = $this->WarninglistEntry->find(
'conditions' => array('warninglist_id' => $id), 'column',
'fields' => array('WarninglistEntry.value') [
)); 'conditions' => ['warninglist_id' => $id],
'fields' => ['WarninglistEntry.value'],
]
);
$this->cacheWarninglistEntries($entries, $id); $this->cacheWarninglistEntries($entries, $id);
return $entries; return $entries;
} }
/** /**
* For 'hostname', 'string' and 'cidr' warninglist type, values are just in keys to save memory. * For 'hostname', 'string' and 'cidr' warninglist type, values are just in keys to save memory.
* *
* @param array $warninglist * @param array $warninglist the warninglist
* @return array * @return array
*/ */
public function getFilteredEntries(array $warninglist) public function getFilteredEntries(array $warninglist)
@ -579,13 +659,13 @@ class WarninglistsTable extends AppTable
$output[$v] = true; $output[$v] = true;
} }
$values = $output; $values = $output;
} else if ($warninglist['Warninglist']['type'] === 'string') { } elseif ($warninglist['Warninglist']['type'] === 'string') {
$output = []; $output = [];
foreach ($values as $v) { foreach ($values as $v) {
$output[$v] = true; $output[$v] = true;
} }
$values = $output; $values = $output;
} else if ($warninglist['Warninglist']['type'] === 'cidr') { } elseif ($warninglist['Warninglist']['type'] === 'cidr') {
$values = new CidrTool($values); $values = new CidrTool($values);
} }
@ -595,7 +675,7 @@ class WarninglistsTable extends AppTable
} }
/** /**
* @param array $object * @param array $object the object to check
* @param array|null $warninglists If null, all enabled warninglists will be used * @param array|null $warninglists If null, all enabled warninglists will be used
* @return array * @return array
*/ */
@ -610,25 +690,26 @@ class WarninglistsTable extends AppTable
if (in_array('ALL', $list['types'], true) || in_array($object['type'], $list['types'], true)) { if (in_array('ALL', $list['types'], true) || in_array($object['type'], $list['types'], true)) {
$result = $this->checkValue($this->getFilteredEntries($list), $object['value'], $object['type'], $list['Warninglist']['type']); $result = $this->checkValue($this->getFilteredEntries($list), $object['value'], $object['type'], $list['Warninglist']['type']);
if ($result !== false) { if ($result !== false) {
$object['warnings'][] = array( $object['warnings'][] = [
'match' => $result[0], 'match' => $result[0],
'value' => $result[1], 'value' => $result[1],
'warninglist_id' => $list['Warninglist']['id'], 'warninglist_id' => $list['Warninglist']['id'],
'warninglist_name' => $list['Warninglist']['name'], 'warninglist_name' => $list['Warninglist']['name'],
'warninglist_category' => $list['Warninglist']['category'], 'warninglist_category' => $list['Warninglist']['category'],
); ];
} }
} }
} }
} }
return $object; return $object;
} }
/** /**
* @param array|CidrTool $listValues * @param array|\App\Lib\Tools\CidrTool $listValues the values of the list
* @param string $value * @param string $value the value to check
* @param string $type * @param string $type the type of the attribute
* @param string $listType * @param string $listType the type of the list
* @return array|false [Matched value, attribute value that matched] * @return array|false [Matched value, attribute value that matched]
*/ */
public function checkValue($listValues, $value, $type, $listType) public function checkValue($listValues, $value, $type, $listType)
@ -636,7 +717,7 @@ class WarninglistsTable extends AppTable
if ($type === 'malware-sample' || strpos($type, '|') !== false) { if ($type === 'malware-sample' || strpos($type, '|') !== false) {
$value = explode('|', $value, 2); $value = explode('|', $value, 2);
} else { } else {
$value = array($value); $value = [$value];
} }
foreach ($value as $v) { foreach ($value as $v) {
if ($listType === 'cidr') { if ($listType === 'cidr') {
@ -656,14 +737,15 @@ class WarninglistsTable extends AppTable
return [$result, $v]; return [$result, $v];
} }
} }
return false; return false;
} }
/** /**
* Check for exact match. * Check for exact match.
* *
* @param array $listValues * @param array $listValues the values of the list
* @param string $value * @param string $value the value to check
* @return false * @return false
*/ */
private function __evalString($listValues, $value) private function __evalString($listValues, $value)
@ -671,9 +753,17 @@ class WarninglistsTable extends AppTable
if (isset($listValues[$value])) { if (isset($listValues[$value])) {
return $value; return $value;
} }
return false; return false;
} }
/**
* Check for substring match.
*
* @param array $listValues the values of the list
* @param string $value the value to check
* @return false
*/
private function __evalSubString($listValues, $value) private function __evalSubString($listValues, $value)
{ {
foreach ($listValues as $listValue) { foreach ($listValues as $listValue) {
@ -681,9 +771,17 @@ class WarninglistsTable extends AppTable
return $listValue; return $listValue;
} }
} }
return false; return false;
} }
/**
* Check for hostname match.
*
* @param array $listValues the values of the list
* @param string $value the value to check
* @return false
*/
private function __evalHostname($listValues, $value) private function __evalHostname($listValues, $value)
{ {
// php's parse_url is dumb, so let's use some hacky workarounds // php's parse_url is dumb, so let's use some hacky workarounds
@ -711,9 +809,17 @@ class WarninglistsTable extends AppTable
return $rebuilt; return $rebuilt;
} }
} }
return false; return false;
} }
/**
* Check for regex match.
*
* @param array $listValues the values of the list
* @param string $value the value to check
* @return false
*/
private function __evalRegex($listValues, $value) private function __evalRegex($listValues, $value)
{ {
foreach ($listValues as $listValue) { foreach ($listValues as $listValue) {
@ -721,6 +827,7 @@ class WarninglistsTable extends AppTable
return $listValue; return $listValue;
} }
} }
return false; return false;
} }
@ -729,10 +836,13 @@ class WarninglistsTable extends AppTable
*/ */
public function fetchTLDLists() public function fetchTLDLists()
{ {
$tldLists = $this->find('column', array( $tldLists = $this->find(
'conditions' => array('name IN' => Warninglist::TLDS), 'column',
'fields' => array('id') [
)); 'conditions' => ['name IN' => Warninglist::TLDS],
'fields' => ['id'],
]
);
$tlds = []; $tlds = [];
foreach ($tldLists as $warninglistId) { foreach ($tldLists as $warninglistId) {
$tlds = array_merge($tlds, $this->getWarninglistEntries($warninglistId)); $tlds = array_merge($tlds, $this->getWarninglistEntries($warninglistId));
@ -741,6 +851,7 @@ class WarninglistsTable extends AppTable
if (!in_array('onion', $tlds, true)) { if (!in_array('onion', $tlds, true)) {
$tlds[] = 'onion'; $tlds[] = 'onion';
} }
return $tlds; return $tlds;
} }
@ -749,19 +860,23 @@ class WarninglistsTable extends AppTable
*/ */
public function fetchSecurityVendorDomains() public function fetchSecurityVendorDomains()
{ {
$securityVendorList = $this->find('column', array( $securityVendorList = $this->find(
'conditions' => array('name' => 'List of known domains used by automated malware analysis services & security vendors'), 'column',
'fields' => array('id') [
)); 'conditions' => ['name' => 'List of known domains used by automated malware analysis services & security vendors'],
'fields' => ['id'],
]
);
$domains = []; $domains = [];
foreach ($securityVendorList as $warninglistId) { foreach ($securityVendorList as $warninglistId) {
$domains = array_merge($domains, $this->getWarninglistEntries($warninglistId)); $domains = array_merge($domains, $this->getWarninglistEntries($warninglistId));
} }
return $domains; return $domains;
} }
/** /**
* @param array $attribute * @param array $attribute the attribute to filter
* @param array|null $warninglists If null, all enabled warninglists will be used * @param array|null $warninglists If null, all enabled warninglists will be used
* @return bool * @return bool
*/ */
@ -779,33 +894,35 @@ class WarninglistsTable extends AppTable
} }
} }
} }
return true; return true;
} }
public function missingTldLists() // public function missingTldLists()
{ // {
$missingTldLists = array(); // $missingTldLists = [];
foreach (Warninglist::TLDS as $tldList) { // foreach (Warninglist::TLDS as $tldList) {
$temp = $this->find('first', array( // $temp = $this->find('first', [
'recursive' => -1, // 'recursive' => -1,
'conditions' => array('Warninglist.name' => $tldList), // 'conditions' => ['Warninglist.name' => $tldList],
'fields' => array('Warninglist.id') // 'fields' => ['Warninglist.id'],
)); // ]);
if (empty($temp)) { // if (empty($temp)) {
$missingTldLists[] = $tldList; // $missingTldLists[] = $tldList;
} // }
} // }
return $missingTldLists;
} // return $missingTldLists;
// }
/** /**
* @param array|null $data * @param array|null $data the data to save
* @param bool $validate * @param bool $validate whether to validate the data
* @param array $fieldList * @param array $fieldList the fields to save
* @return array|bool|mixed|null * @return array|bool|mixed|null
* @throws Exception * @throws \Exception
*/ */
public function save($data = null, $validate = true, $fieldList = array()) public function save($data = null, $validate = true, $fieldList = [])
{ {
$db = $this->getDataSource(); $db = $this->getDataSource();
$transactionBegun = $db->begin(); $transactionBegun = $db->begin();
@ -825,7 +942,7 @@ class WarninglistsTable extends AppTable
$this->WarninglistEntry->deleteAll(['warninglist_id' => $id], false); $this->WarninglistEntry->deleteAll(['warninglist_id' => $id], false);
$entriesToInsert = []; $entriesToInsert = [];
foreach ($data['WarninglistEntry'] as $entry) { foreach ($data['WarninglistEntry'] as $entry) {
$entriesToInsert[] = [$entry['value'], isset($entry['comment']) ? $entry['comment'] : null, $id]; $entriesToInsert[] = [$entry['value'], $entry['comment'] ?? null, $id];
} }
$db->insertMulti( $db->insertMulti(
$this->WarninglistEntry->table, $this->WarninglistEntry->table,
@ -864,7 +981,10 @@ class WarninglistsTable extends AppTable
} }
/** /**
* @param bool $created * post full save actions
*
* @param bool $created True for a new creation, false for an edit
* @param array $data the data that was saved
* @return void * @return void
*/ */
private function afterFullSave($created, array $data) private function afterFullSave($created, array $data)
@ -874,17 +994,20 @@ class WarninglistsTable extends AppTable
} }
if ($this->pubToZmq('warninglist')) { if ($this->pubToZmq('warninglist')) {
$warninglist = $this->find('first', [ $warninglist = $this->find(
'conditions' => ['id' => $data['Warninglist']['id']], 'first',
'contains' => ['WarninglistEntry', 'WarninglistType'], [
]); 'conditions' => ['id' => $data['Warninglist']['id']],
'contains' => ['WarninglistEntry', 'WarninglistType'],
]
);
$pubSubTool = $this->getPubSubTool(); $pubSubTool = $this->getPubSubTool();
$pubSubTool->warninglist_save($warninglist, $created ? 'add' : 'edit'); $pubSubTool->warninglist_save($warninglist, $created ? 'add' : 'edit');
} }
} }
/** /**
* @param string $input * @param string $input the input to parse
* @return array * @return array
*/ */
public function parseFreetext($input) public function parseFreetext($input)
@ -896,15 +1019,21 @@ class WarninglistsTable extends AppTable
$entries = []; $entries = [];
foreach (explode("\n", trim($input)) as $entry) { foreach (explode("\n", trim($input)) as $entry) {
$valueAndComment = explode("#", $entry, 2); $valueAndComment = explode('#', $entry, 2);
$entries[] = [ $entries[] = [
'value' => trim($valueAndComment[0]), 'value' => trim($valueAndComment[0]),
'comment' => count($valueAndComment) === 2 ? trim($valueAndComment[1]) : null, 'comment' => count($valueAndComment) === 2 ? trim($valueAndComment[1]) : null,
]; ];
} }
return $entries; return $entries;
} }
/**
* get the categories
*
* @return array
*/
public function categories() public function categories()
{ {
return [ return [

View File

@ -64,7 +64,7 @@ $fields = [
'type' => 'boolean', 'type' => 'boolean',
'pill' => true 'pill' => true
], ],
]; ];
echo $this->element( echo $this->element(
'/genericElements/SingleViews/single_view', '/genericElements/SingleViews/single_view',

View File

@ -0,0 +1,175 @@
<?php
$fields = [
[
'name' => __('ID'),
'sort' => 'id',
'class' => 'short',
'data_path' => 'id',
// 'element' => 'links',
// 'url' => $baseurl . '/warninglists/view/%s',
],
[
'name' => __('Name'),
'sort' => 'name',
'data_path' => 'name',
],
[
'name' => __('Version'),
'sort' => 'version',
'class' => 'short',
'data_path' => 'version',
],
[
'name' => __('Description'),
'data_path' => 'description',
],
[
'name' => __('Category'),
'sort' => 'category',
'class' => 'short',
'element' => 'custom',
'function' => function (array|\App\Model\Entity\Warninglist $row) use ($possibleCategories) {
return $possibleCategories[$row['category']];
},
],
[
'name' => __('Type'),
'sort' => 'type',
'class' => 'short',
'data_path' => 'type',
],
[
'name' => __('Entries'),
'sort' => 'warninglist_entry_count',
'class' => 'short',
'data_path' => 'warninglist_entry_count',
],
[
'name' => __('Default'),
'sort' => 'default',
'class' => 'short',
'element' => 'boolean',
'data_path' => 'default',
],
[
'name' => __('Enabled'),
'sort' => 'enabled',
'class' => 'short',
'element' => 'toggle',
'data_path' => 'enabled',
'url' => '/warninglists/toggleEnable',
'url_params_vars' => [['datapath' => ['id']]],
'requirement' => $loggedUser['Role']['perm_site_admin'],
],
];
// echo '<div class="index">';
// if ($isSiteAdmin) {
// echo '<div id="hiddenFormDiv">';
// echo $this->Form->create('Warninglist', ['url' => $baseurl . '/warninglists/toggleEnable']);
// echo $this->Form->input('data', ['label' => false, 'style' => 'display:none;']);
// echo $this->Form->end();
// echo '</div>';
// }
echo $this->element(
'/genericElements/IndexTable/index_table',
[
'data' => [
'data' => $data,
'top_bar' => [
'children' => [
// FIXME chri filtering
// [
// 'type' => 'simple',
// 'children' => [
// [
// 'url' => $baseurl . '/warninglists/index',
// 'text' => __('All'),
// 'active' => !isset($passedArgsArray['enabled']),
// ],
// [
// 'url' => $baseurl . '/warninglists/index/enabled:1',
// 'text' => __('Enabled'),
// 'active' => isset($passedArgsArray['enabled']) && $passedArgsArray['enabled'] === '1',
// ],
// [
// 'url' => $baseurl . '/warninglists/index/enabled:0',
// 'text' => __('Disabled'),
// 'active' => isset($passedArgsArray['enabled']) && $passedArgsArray['enabled'] === '0',
// ],
// ],
// ],
[
'type' => 'search',
'button' => __('Filter'),
'placeholder' => __('Enter value to search'),
'data' => '',
'searchKey' => 'value',
'allowFilering' => true,
],
],
],
'title' => __('Warninglists'),
'primary_id_path' => 'id',
'fields' => $fields,
'actions' => [
[
'url' => '/warninglists/view',
'url_params_data_paths' => ['id'],
'icon' => 'eye',
],
// [
// 'title' => __('Enable'),
// 'icon' => 'play',
// 'onclick' => sprintf('toggleSetting(%s, \'%s\', \'%s\')', 'event', 'warninglist_enable', '[onclick_params_data_path]'),
// 'onclick_params_data_path' => 'id',
// 'complex_requirement' => [
// 'function' => function ($row, $options) use ($loggedUser) {
// return $loggedUser['Role']['perm_site_admin'] && !$options['datapath']['enabled'];
// },
// 'options' => [
// 'datapath' => [
// 'orgc' => 'Event.orgc_id',
// 'enabled' => 'enabled',
// ],
// ],
// ],
// ],
// [
// 'title' => __('Disable'),
// 'icon' => 'stop',
// 'onclick' => sprintf('toggleSetting(%s, \'%s\', \'%s\')', 'event', 'warninglist_enable', '[onclick_params_data_path]'),
// 'onclick_params_data_path' => 'id',
// 'complex_requirement' => [
// 'function' => function ($row, $options) use ($loggedUser) {
// return $loggedUser['Role']['perm_site_admin'] && $options['datapath']['enabled'];
// },
// 'options' => [
// 'datapath' => [
// 'enabled' => 'enabled',
// ],
// ],
// ],
// ],
[
'open_modal' => '/warninglists/edit/[onclick_params_data_path]',
'modal_params_data_path' => 'id',
'icon' => 'edit',
'complex_requirement' => [
'function' => function ($row) use ($loggedUser) {
return $row['default'] == 0 && ($loggedUser['Role']['perm_warninglist'] || $loggedUser['Role']['perm_site_admin']);
},
],
],
[
'open_modal' => '/warninglists/delete/[onclick_params_data_path]',
'modal_params_data_path' => 'id',
'icon' => 'trash',
'requirement' => $loggedUser['Role']['perm_site_admin'],
],
],
],
]
);
// echo '</div>';
// echo $this->element('/genericElements/SideMenu/side_menu', ['menuList' => 'warninglist', 'menuItem' => 'index']);

View File

@ -0,0 +1,105 @@
<?php
echo $this->element(
'genericElements/SingleViews/single_view',
[
'title' => __('Warninglist View'),
'data' => $entity,
'fields' => [
[
'key' => __('ID'),
'path' => 'id'
],
[
'key' => __('Name'),
'path' => 'name'
],
[
'key' => __('Description'),
'path' => 'description'
],
[
'key' => __('Version'),
'path' => 'version'
],
[
'key' => __('Category'),
'path' => 'category',
'function' => function (array|\App\Model\Entity\Warninglist $row) use ($possibleCategories) {
return $possibleCategories[$row['category']];
}
],
[
'key' => __('Type'),
'path' => 'type'
],
[
'key' => __('Accepted attribute types'),
'path' => 'type' // FIXME
]
],
'children' => [
[
'url' => '/warninglists/preview_entries/{{0}}',
'url_params' => ['id'],
'title' => __('Values'),
'elementId' => 'preview_entries_container'
]
]
]
);
// $types = implode(', ', array_column($warninglist['WarninglistType'], 'type'));
// $table_data = [
// ['key' => __('ID'), 'value' => $entity['id']],
// ['key' => __('Name'), 'value' => $entity['name']],
// ['key' => __('Description'), 'value' => $entity['description']],
// ['key' => __('Version'), 'value' => $entity['version']],
// ['key' => __('Category'), 'value' => $possibleCategories[$entity['category']]],
// ['key' => __('Type'), 'value' => $entity['type']],
// ['key' => __('Accepted attribute types'), 'value' => $types],
// [
// 'key' => __('Enabled'),
// 'boolean' => $entity['enabled'],
// 'html' => $me['Role']['perm_warninglist'] ? sprintf(
// ' <a href="%s/warninglists/enableWarninglist/%s%s" title="%s">%s</a>',
// $baseurl,
// h($warninglist['Warninglist']['id']),
// $entity['enabled'] ? '' : '/1',
// $entity['enabled'] ? __('Disable') : __('Enable'),
// $entity['enabled'] ? __('Disable') : __('Enable')
// ) : '',
// ],
// ];
// $values = [];
// foreach ($warninglist['WarninglistEntry'] as $entry) {
// $value = '<span class="warninglist-value">' . h($entry['value']) . '</span>';
// if ($entry['comment']) {
// $value .= ' <span class="warninglist-comment"># ' . h($entry['comment']) . '</span>';
// }
// $values[] = $value;
// }
// echo '<div class="warninglist view">';
// echo sprintf(
// '<div class="row-fluid"><div class="span8" style="margin:0;">%s</div></div><h4>%s</h4>',
// sprintf(
// '<h2>%s</h2>%s',
// h($warninglist['Warninglist']['name']),
// $this->element('genericElements/viewMetaTable', ['table_data' => $table_data])
// ),
// __('Values')
// );
// echo implode('<br>', $values);
// echo '</div>';
// echo $this->element(
// '/genericElements/SideMenu/side_menu',
// [
// 'menuList' => 'warninglist',
// 'menuItem' => 'view',
// 'id' => $entity['id'],
// 'isDefault' => $entity['default'] == 1,
// ]
// );

View File

@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class WarninglistEntriesFixture extends TestFixture
{
public const WARNINGLIST_ENTRY_1_ID = 1;
public const WARNINGLIST_ENTRY_2_ID = 2;
public const WARNINGLIST_ENTRY_3_ID = 3;
public const WARNINGLIST_ENTRY_4_ID = 4;
public const WARNINGLIST_ENTRY_5_ID = 5;
public const WARNINGLIST_ENTRY_6_ID = 6;
public const WARNINGLIST_ENTRY_7_ID = 7;
public const WARNINGLIST_ENTRY_8_ID = 8;
public const WARNINGLIST_ENTRY_9_ID = 9;
public const WARNINGLIST_ENTRY_10_ID = 10;
public const WARNINGLIST_ENTRY_11_ID = 11;
public const WARNINGLIST_ENTRY_12_ID = 12;
public const WARNINGLIST_ENTRY_13_ID = 13;
public const WARNINGLIST_ENTRY_14_ID = 14;
public function init(): void
{
$this->records = [
// enabled
[
'id' => self::WARNINGLIST_ENTRY_1_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'value' => '1.1.1.0/24',
'comment' => '',
],
[
'id' => self::WARNINGLIST_ENTRY_2_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'value' => '2.2.0.0/16',
'comment' => '',
],
[
'id' => self::WARNINGLIST_ENTRY_3_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'value' => '1.1.1.0/32',
'comment' => '',
],
// disabled
[
'id' => self::WARNINGLIST_ENTRY_4_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_2_ID,
'value' => '4.4.4.0/24',
'comment' => '',
],
// hostname
[
'id' => self::WARNINGLIST_ENTRY_5_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_HOSTNAME_ID,
'value' => 'vm.misp-project.org',
'comment' => '',
],
// substr
[
'id' => self::WARNINGLIST_ENTRY_6_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_SUBSTR_ID,
'value' => 'misp',
'comment' => '',
],
// str
[
'id' => self::WARNINGLIST_ENTRY_7_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_STR_ID,
'value' => 'vm.misp-project.org',
'comment' => '',
],
// regex
[
'id' => self::WARNINGLIST_ENTRY_8_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_REGEX_ID,
'value' => '/misp-[a-z]\.org$/',
'comment' => '',
],
];
// TODO import warninglists from files to have larger datasets
parent::init();
}
}

View File

@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use Cake\TestSuite\Fixture\TestFixture;
class WarninglistTypesFixture extends TestFixture
{
public const WARNINGLIST_TYPE_1_ID = 1;
public const WARNINGLIST_TYPE_2_ID = 2;
public const WARNINGLIST_TYPE_3_ID = 3;
public const WARNINGLIST_TYPE_4_ID = 4;
public const WARNINGLIST_TYPE_5_ID = 5;
public const WARNINGLIST_TYPE_6_ID = 6;
public const WARNINGLIST_TYPE_7_ID = 7;
public const WARNINGLIST_TYPE_8_ID = 8;
public const WARNINGLIST_TYPE_9_ID = 9;
public const WARNINGLIST_TYPE_10_ID = 10;
public function init(): void
{
$this->records = [
// CIDR
[
'id' => self::WARNINGLIST_TYPE_1_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'type' => 'ip-src',
],
[
'id' => self::WARNINGLIST_TYPE_2_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'type' => 'ip-dst',
],
[
'id' => self::WARNINGLIST_TYPE_3_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_CIDR_1_ID,
'type' => 'domain|ip',
],
// HOSTNAME
[
'id' => self::WARNINGLIST_TYPE_4_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_HOSTNAME_ID,
'type' => 'url',
],
[
'id' => self::WARNINGLIST_TYPE_5_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_HOSTNAME_ID,
'type' => 'domain|ip',
],
[
'id' => self::WARNINGLIST_TYPE_6_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_HOSTNAME_ID,
'type' => 'hostname',
],
[
'id' => self::WARNINGLIST_TYPE_7_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_HOSTNAME_ID,
'type' => 'domain',
],
// SUBSTR
[
'id' => self::WARNINGLIST_TYPE_8_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_SUBSTR_ID,
'type' => 'domain',
],
// STR
[
'id' => self::WARNINGLIST_TYPE_9_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_STR_ID,
'type' => 'domain',
],
// REGEX
[
'id' => self::WARNINGLIST_TYPE_10_ID,
'warninglist_id' => WarninglistsFixture::WARNINGLIST_REGEX_ID,
'type' => 'domain',
],
];
parent::init();
}
}

View File

@ -0,0 +1,98 @@
<?php
declare(strict_types=1);
namespace App\Test\Fixture;
use App\Model\Entity\Warninglist;
use Cake\TestSuite\Fixture\TestFixture;
class WarninglistsFixture extends TestFixture
{
public $connection = 'test';
public const WARNINGLIST_CIDR_1_ID = 1;
public const WARNINGLIST_CIDR_1_NAME = 'disabled cidr warninglist';
public const WARNINGLIST_CIDR_2_ID = 2;
public const WARNINGLIST_CIDR_2_NAME = 'enabled cidr warninglist';
public const WARNINGLIST_HOSTNAME_ID = 3;
public const WARNINGLIST_HOSTNAME_NAME = 'enabled hostname warninglist';
public const WARNINGLIST_SUBSTR_ID = 4;
public const WARNINGLIST_SUBSTR_NAME = 'enabled substr warninglist';
public const WARNINGLIST_STR_ID = 5;
public const WARNINGLIST_STR_NAME = 'enabled string warninglist';
public const WARNINGLIST_REGEX_ID = 6;
public const WARNINGLIST_REGEX_NAME = 'enabled regex warninglist';
public function init(): void
{
$this->records = [
[
'id' => self::WARNINGLIST_CIDR_1_ID,
'name' => self::WARNINGLIST_CIDR_1_NAME,
'type' => 'cidr',
'description' => 'test disabled cidr warninglist description',
'version' => 1,
'enabled' => false,
'default' => false,
'category' => Warninglist::CATEGORY_FALSE_POSITIVE,
],
[
'id' => self::WARNINGLIST_CIDR_2_ID,
'name' => self::WARNINGLIST_CIDR_2_NAME,
'type' => 'cidr',
'description' => 'test enabled cidr warninglist description',
'version' => 1,
'enabled' => true,
'default' => false,
'category' => Warninglist::CATEGORY_KNOWN,
],
[
'id' => self::WARNINGLIST_HOSTNAME_ID,
'name' => self::WARNINGLIST_HOSTNAME_NAME,
'type' => 'hostname',
'description' => 'test enabled hostname warninglist description',
'version' => 1,
'enabled' => true,
'default' => false,
'category' => Warninglist::CATEGORY_FALSE_POSITIVE,
],
[
'id' => self::WARNINGLIST_SUBSTR_ID,
'name' => self::WARNINGLIST_SUBSTR_NAME,
'type' => 'hostname',
'description' => 'test enabled substring warninglist description',
'version' => 1,
'enabled' => true,
'default' => false,
'category' => Warninglist::CATEGORY_FALSE_POSITIVE,
],
[
'id' => self::WARNINGLIST_STR_ID,
'name' => self::WARNINGLIST_STR_NAME,
'type' => 'hostname',
'description' => 'test enabled string warninglist description',
'version' => 1,
'enabled' => true,
'default' => false,
'category' => Warninglist::CATEGORY_FALSE_POSITIVE,
],
[
'id' => self::WARNINGLIST_REGEX_ID,
'name' => self::WARNINGLIST_REGEX_NAME,
'type' => 'hostname',
'description' => 'test enabled regex warninglist description',
'version' => 1,
'enabled' => true,
'default' => false,
'category' => Warninglist::CATEGORY_FALSE_POSITIVE,
],
];
parent::init();
}
}

View File

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Api\Warninglists;
use App\Test\Fixture\AuthKeysFixture;
use App\Test\Fixture\WarninglistsFixture;
use App\Test\Helper\ApiTestTrait;
use Cake\TestSuite\TestCase;
class IndexWarninglistsApiTest extends TestCase
{
use ApiTestTrait;
protected const ENDPOINT = '/warninglists/index';
protected $fixtures = [
'app.Organisations',
'app.Roles',
'app.Users',
'app.AuthKeys',
'app.Warninglists',
'app.WarninglistEntries',
'app.WarninglistTypes',
];
public function testIndexWarninglistsAsAdmin(): void
{
$this->skipOpenApiValidations();
$this->setAuthToken(AuthKeysFixture::ADMIN_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"name": "%s"', WarninglistsFixture::WARNINGLIST_CIDR_1_NAME));
}
public function testIndexWarninglistsAsUser(): void
{
$this->skipOpenApiValidations();
$this->setAuthToken(AuthKeysFixture::REGULAR_USER_API_KEY);
$this->get(self::ENDPOINT);
$this->assertResponseOk();
$this->assertResponseContains(sprintf('"name": "%s"', WarninglistsFixture::WARNINGLIST_CIDR_1_NAME));
}
}

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace App\Test\TestCase\Model\Table;
use App\Model\Table\WarninglistsTable;
use App\Test\Fixture\OrganisationsFixture;
use App\Test\Fixture\UsersFixture;
use Cake\TestSuite\TestCase;
/**
* App\Model\Table\WarninglistsTable Test Case
*/
class WarninglistsTableTest extends TestCase
{
/**
* Test subject
*
* @var \App\Model\Table\WarninglistsTable
*/
protected $Warninglists;
protected $user;
/**
* Fixtures
*
* @var array
*/
protected $fixtures = [
'app.Warninglists',
'app.WarninglistEntries',
'app.Users',
'app.Organisations',
];
/**
* setUp method
*
* @return void
*/
protected function setUp(): void
{
parent::setUp();
$config = $this->getTableLocator()->exists('Warninglists') ? [] : ['className' => WarninglistsTable::class];
$this->Warninglists = $this->getTableLocator()->get('Warninglists', $config);
$this->user = [
'id' => UsersFixture::USER_REGULAR_USER_ID,
'org_id' => OrganisationsFixture::ORGANISATION_A_ID,
'email' => UsersFixture::USER_REGULAR_USER_EMAIL,
];
}
/**
* tearDown method
*
* @return void
*/
protected function tearDown(): void
{
unset($this->Warninglists);
parent::tearDown();
}
/**
* Test initialize method
*
* @return void
*/
public function testInitialize(): void
{
$this->markTestIncomplete('Not implemented yet.');
}
/**
* Test validationDefault method
*
* @return void
*/
public function testValidationDefault(): void
{
$this->markTestIncomplete('Not implemented yet.');
}
public function testParseFreetext(): void
{
$faker = \Faker\Factory::create();
$items = [];
for ($i = 0; $i < 10; $i++) {
$items[] = $faker->domainName() . " #" . $faker->sentence();
}
$items[] = ""; // empty to verify trim
$items[] = " # "; // empty to verify trim
$freetext = implode("\n", $items);
$result = WarninglistsTable::parseFreetext($freetext);
$this->assertEquals(count($result), 10);
}
}