mirror of https://github.com/MISP/MISP
Merge pull request #8278 from JakubOnderka/warninglist-import-export-test
new: [test] Warninglist import/exportpull/8347/head
commit
12906c13b6
|
@ -7,6 +7,7 @@ App::uses('JsonTool', 'Tools');
|
|||
/**
|
||||
* @property Server $Server
|
||||
* @property Feed $Feed
|
||||
* @property Warninglist $warninglist
|
||||
* @property AdminSetting $AdminSetting
|
||||
*/
|
||||
class AdminShell extends AppShell
|
||||
|
@ -19,6 +20,9 @@ class AdminShell extends AppShell
|
|||
$parser->addSubcommand('updateJSON', array(
|
||||
'help' => __('Update the JSON definitions of MISP.'),
|
||||
));
|
||||
$parser->addSubcommand('updateWarningLists', array(
|
||||
'help' => __('Update the JSON definition of warninglists.'),
|
||||
));
|
||||
$parser->addSubcommand('setSetting', [
|
||||
'help' => __('Set setting in PHP config file.'),
|
||||
'parser' => [
|
||||
|
@ -312,7 +316,6 @@ class AdminShell extends AppShell
|
|||
|
||||
public function updateWarningLists()
|
||||
{
|
||||
$this->ConfigLoad->execute();
|
||||
$result = $this->Warninglist->update();
|
||||
$success = count($result['success']);
|
||||
$fails = count($result['fails']);
|
||||
|
|
|
@ -479,39 +479,70 @@ class RestResponseComponent extends Component
|
|||
return [];
|
||||
}
|
||||
|
||||
public function saveFailResponse($controller, $action, $id = false, $validationErrors, $format = false, $data = null)
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param string $action
|
||||
* @param int|false $id
|
||||
* @param mixed $validationErrors
|
||||
* @param string|false $format
|
||||
* @param mixed $data
|
||||
* @return CakeResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function saveFailResponse($controller, $action, $id, $validationErrors, $format = false, $data = null)
|
||||
{
|
||||
$response = array();
|
||||
$action = $this->__dissectAdminRouting($action);
|
||||
$stringifiedAction = $action['action'];
|
||||
if (isset(self::CONVERT_ACTION_TO_MESSAGE[$controller][$action['action']])) {
|
||||
$stringifiedAction = self::CONVERT_ACTION_TO_MESSAGE[$controller][$action['action']];
|
||||
if (isset(self::CONVERT_ACTION_TO_MESSAGE[$controller][$stringifiedAction])) {
|
||||
$stringifiedAction = self::CONVERT_ACTION_TO_MESSAGE[$controller][$stringifiedAction];
|
||||
}
|
||||
$response['saved'] = false;
|
||||
$response['name'] = 'Could not ' . $stringifiedAction . ' ' . Inflector::singularize($controller);
|
||||
$response['message'] = $response['name'];
|
||||
$message = 'Could not ' . $stringifiedAction . ' ' . Inflector::singularize($controller);
|
||||
|
||||
$response = [
|
||||
'saved' => false,
|
||||
'name' => $message,
|
||||
'message' => $message,
|
||||
'url' => $this->__generateURL($action, $controller, $id),
|
||||
'errors' => $validationErrors,
|
||||
];
|
||||
if ($data !== null) {
|
||||
$response['data'] = $data;
|
||||
}
|
||||
$response['url'] = $this->__generateURL($action, $controller, $id);
|
||||
$response['errors'] = $validationErrors;
|
||||
if ($id) {
|
||||
$response['id'] = $id;
|
||||
}
|
||||
return $this->__sendResponse($response, 403, $format);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $controller
|
||||
* @param string $action
|
||||
* @param int|false $id
|
||||
* @param string|false $format
|
||||
* @param string|false $message
|
||||
* @param mixed $data
|
||||
* @return CakeResponse
|
||||
* @throws Exception
|
||||
*/
|
||||
public function saveSuccessResponse($controller, $action, $id = false, $format = false, $message = false, $data = null)
|
||||
{
|
||||
$action = $this->__dissectAdminRouting($action);
|
||||
if (!$message) {
|
||||
$message = Inflector::singularize($controller) . ' ' . $action['action'] . ((substr($action['action'], -1) == 'e') ? 'd' : 'ed');
|
||||
$message = Inflector::singularize($controller) . ' ' . $action['action'] . ((substr($action['action'], -1) === 'e') ? 'd' : 'ed');
|
||||
}
|
||||
$response['saved'] = true;
|
||||
$response['success'] = true;
|
||||
$response['name'] = $message;
|
||||
$response['message'] = $response['name'];
|
||||
$response = [
|
||||
'saved' => true,
|
||||
'success' => true,
|
||||
'name' => $message,
|
||||
'message' => $message,
|
||||
'url' => $this->__generateURL($action, $controller, $id),
|
||||
];
|
||||
if ($data !== null) {
|
||||
$response['data'] = $data;
|
||||
}
|
||||
$response['url'] = $this->__generateURL($action, $controller, $id);
|
||||
if ($id) {
|
||||
$response['id'] = $id;
|
||||
}
|
||||
return $this->__sendResponse($response, 200, $format);
|
||||
}
|
||||
|
||||
|
|
|
@ -360,9 +360,7 @@ class WarninglistsController extends AppController
|
|||
|
||||
public function import()
|
||||
{
|
||||
if (!$this->request->is('post')) {
|
||||
throw new MethodNotAllowedException(__('This function only accepts POST requests.'));
|
||||
}
|
||||
$this->request->allowMethod(['post']);
|
||||
|
||||
if (empty($this->request->data)) {
|
||||
throw new BadRequestException(__('No valid data received.'));
|
||||
|
@ -378,11 +376,11 @@ class WarninglistsController extends AppController
|
|||
throw new BadRequestException(__('No valid data received: `list` field is not array'));
|
||||
}
|
||||
|
||||
$id = $this->Warninglist->import($this->request->data);
|
||||
if (is_int($id)) {
|
||||
try {
|
||||
$id = $this->Warninglist->import($this->request->data);
|
||||
return $this->RestResponse->saveSuccessResponse('Warninglist', 'import', $id, false, __('Warninglist imported'));
|
||||
} else {
|
||||
return $this->RestResponse->saveFailResponse('Warninglist', 'import', false, $id);
|
||||
} catch (Exception $e) {
|
||||
return $this->RestResponse->saveFailResponse('Warninglist', 'import', false, $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,7 @@ class Warninglist extends AppModel
|
|||
|
||||
public function update()
|
||||
{
|
||||
// Existing default warninglists
|
||||
// Fetch existing default warninglists
|
||||
$existingWarninglist = $this->find('all', [
|
||||
'fields' => ['id', 'name', 'version', 'enabled'],
|
||||
'recursive' => -1,
|
||||
|
@ -276,7 +276,7 @@ class Warninglist extends AppModel
|
|||
$existingWarninglist = array_column(array_column($existingWarninglist, 'Warninglist'), null, 'name');
|
||||
|
||||
$directories = glob(APP . 'files' . DS . 'warninglists' . DS . 'lists' . DS . '*', GLOB_ONLYDIR);
|
||||
$updated = array('success' => [], 'fails' => []);
|
||||
$result = ['success' => [], 'fails' => []];
|
||||
foreach ($directories as $dir) {
|
||||
$list = FileAccessTool::readJsonFromFile($dir . DS . 'list.json');
|
||||
if (!isset($list['version'])) {
|
||||
|
@ -289,19 +289,19 @@ class Warninglist extends AppModel
|
|||
}
|
||||
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']);
|
||||
try {
|
||||
$result = $this->__updateList($list, $current);
|
||||
$result['success'][$result] = ['name' => $list['name'], 'new' => $list['version']];
|
||||
if (!empty($current)) {
|
||||
$updated['success'][$result]['old'] = $current['version'];
|
||||
$result['success'][$result]['old'] = $current['version'];
|
||||
}
|
||||
} else {
|
||||
$updated['fails'][] = array('name' => $list['name'], 'fail' => json_encode($result));
|
||||
} catch (Exception $e) {
|
||||
$result['fails'][] = ['name' => $list['name'], 'fail' => $e->getMessage()];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->regenerateWarninglistCaches();
|
||||
return $updated;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function quickDelete($id)
|
||||
|
@ -325,7 +325,7 @@ class Warninglist extends AppModel
|
|||
/**
|
||||
* Import single warninglist
|
||||
* @param array $list
|
||||
* @return array|int|string
|
||||
* @return int Warninglist ID
|
||||
* @throws Exception
|
||||
*/
|
||||
public function import(array $list)
|
||||
|
@ -341,29 +341,30 @@ class Warninglist extends AppModel
|
|||
}
|
||||
|
||||
$id = $this->__updateList($list, $existingWarninglist ? $existingWarninglist['Warninglist']: [], false);
|
||||
if (is_int($id)) {
|
||||
$this->regenerateWarninglistCaches($id);
|
||||
}
|
||||
$this->regenerateWarninglistCaches($id);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $list
|
||||
* @param array $current
|
||||
* @param array $existing
|
||||
* @param bool $default
|
||||
* @return array|int|string
|
||||
* @return int Warninglist ID
|
||||
* @throws Exception
|
||||
*/
|
||||
private function __updateList(array $list, array $current, $default = true)
|
||||
private function __updateList(array $list, array $existing, $default = true)
|
||||
{
|
||||
$list['enabled'] = 0;
|
||||
$warninglist = array();
|
||||
if (!empty($current)) {
|
||||
if ($current['enabled']) {
|
||||
$warninglist = [];
|
||||
if (!empty($existing)) {
|
||||
if ($existing['enabled']) {
|
||||
$list['enabled'] = 1;
|
||||
}
|
||||
$warninglist['Warninglist']['id'] = $current['id']; // keep list ID
|
||||
$this->quickDelete($current['id']);
|
||||
$warninglist['Warninglist']['id'] = $existing['id']; // keep list ID
|
||||
// Delete all dependencies
|
||||
$this->WarninglistEntry->deleteAll(['WarninglistEntry.warninglist_id' => $existing['id']], false);
|
||||
$this->WarninglistType->deleteAll(['WarninglistType.warninglist_id' => $existing['id']], false);
|
||||
}
|
||||
$fieldsToSave = array('name', 'version', 'description', 'type', 'enabled');
|
||||
foreach ($fieldsToSave as $fieldToSave) {
|
||||
|
@ -374,7 +375,7 @@ class Warninglist extends AppModel
|
|||
}
|
||||
$this->create();
|
||||
if (!$this->save($warninglist)) {
|
||||
return $this->validationErrors;
|
||||
throw new Exception("Could not save warninglist because of validation errors: " . json_encode($this->validationErrors));
|
||||
}
|
||||
|
||||
$db = $this->getDataSource();
|
||||
|
@ -404,13 +405,13 @@ class Warninglist extends AppModel
|
|||
}
|
||||
}
|
||||
if (!$result) {
|
||||
return 'Could not insert values.';
|
||||
throw new Exception('Could not insert values.');
|
||||
}
|
||||
|
||||
if (empty($list['matching_attributes'])) {
|
||||
$list['matching_attributes'] = ['ALL'];
|
||||
}
|
||||
$values = array();
|
||||
$values = [];
|
||||
foreach ($list['matching_attributes'] as $type) {
|
||||
$values[] = array('type' => $type, 'warninglist_id' => $warninglistId);
|
||||
}
|
||||
|
|
|
@ -690,6 +690,10 @@ class TestComprehensive(unittest.TestCase):
|
|||
wl = request(self.admin_misp_connector, 'POST', 'warninglists/add', data=warninglist)
|
||||
check_response(wl)
|
||||
|
||||
exported = request(self.admin_misp_connector, 'GET', f'warninglists/export/{wl["Warninglist"]["id"]}')
|
||||
self.assertIn('name', exported)
|
||||
self.assertEqual('Test', exported['name'])
|
||||
|
||||
check_response(self.admin_misp_connector.enable_warninglist(wl["Warninglist"]["id"]))
|
||||
|
||||
response = self.admin_misp_connector.values_in_warninglist("1.2.3.4")
|
||||
|
@ -717,9 +721,21 @@ class TestComprehensive(unittest.TestCase):
|
|||
response = self.admin_misp_connector.values_in_warninglist("2.3.4.5")
|
||||
self.assertEqual(0, len(response))
|
||||
|
||||
# Update by importing
|
||||
response = request(self.admin_misp_connector, 'POST', f'warninglists/import', exported)
|
||||
check_response(response)
|
||||
|
||||
response = request(self.admin_misp_connector, 'POST', f'warninglists/delete/{wl["Warninglist"]["id"]}')
|
||||
check_response(response)
|
||||
|
||||
# Create new warninglist by importing under different name
|
||||
exported["name"] = "Test2"
|
||||
response = request(self.admin_misp_connector, 'POST', f'warninglists/import', exported)
|
||||
check_response(response)
|
||||
|
||||
response = request(self.admin_misp_connector, 'POST', f'warninglists/delete/{response["id"]}')
|
||||
check_response(response)
|
||||
|
||||
def test_protected_event(self):
|
||||
event = create_simple_event()
|
||||
event = check_response(self.admin_misp_connector.add_event(event))
|
||||
|
|
Loading…
Reference in New Issue