MISP/app/Controller/WorkflowsController.php

270 lines
10 KiB
PHP
Raw Normal View History

<?php
App::uses('AppController', 'Controller');
class WorkflowsController extends AppController
{
public $components = array(
'RequestHandler'
);
public function beforeFilter()
{
parent::beforeFilter();
$this->Security->unlockedActions[] = 'hasAcyclicGraph';
$requirementErrors = [];
if (empty(Configure::read('MISP.background_jobs'))) {
$requirementErrors[] = __('Background workers must be enabled to use workflows');
$this->render('error');
}
try {
$this->Workflow->setupRedisWithException();
} catch (Exception $e) {
$requirementErrors[] = $e->getMessage();
}
if (!empty($requirementErrors)) {
$this->set('requirementErrors', $requirementErrors);
$this->render('error');
}
}
public function index()
{
2022-05-04 00:01:02 +02:00
$params = [
'filters' => ['name', 'uuid'],
'quickFilters' => ['name', 'uuid'],
2022-05-04 00:01:02 +02:00
];
$this->CRUD->index($params);
if ($this->IndexFilter->isRest()) {
return $this->restResponsePayload;
}
$this->set('menuData', array('menuList' => 'workflows', 'menuItem' => 'index'));
}
public function rebuildRedis()
{
$this->Workflow->rebuildRedis();
}
2022-05-04 00:01:02 +02:00
public function edit($id)
{
2022-05-04 00:01:02 +02:00
$this->set('id', $id);
$savedWorkflow = $this->Workflow->fetchWorkflow($id);
if ($this->request->is('post') || $this->request->is('put')) {
$newWorkflow = $this->request->data;
$newWorkflow['Workflow']['data'] = JsonTool::decode($newWorkflow['Workflow']['data']);
$newWorkflow = $this->__applyDataFromSavedWorkflow($newWorkflow, $savedWorkflow);
$errors = $this->Workflow->editWorkflow($newWorkflow);
$redirectTarget = ['action' => 'view', $id];
if (!empty($errors)) {
return $this->__getFailResponseBasedOnContext($errors, null, 'edit', $this->Workflow->id, $redirectTarget);
} else {
$successMessage = __('Workflow saved.');
$savedWorkflow =$this->Workflow->fetchWorkflow($id);
return $this->__getSuccessResponseBasedOnContext($successMessage, $savedWorkflow, 'edit', false, $redirectTarget);
}
} else {
$savedWorkflow['Workflow']['data'] = JsonTool::encode($savedWorkflow['Workflow']['data']);
$this->request->data = $savedWorkflow;
2022-05-04 00:01:02 +02:00
}
2022-05-04 00:01:02 +02:00
$this->set('menuData', array('menuList' => 'workflows', 'menuItem' => 'edit'));
$this->render('add');
}
2022-05-04 00:01:02 +02:00
public function delete($id)
{
2022-05-04 00:01:02 +02:00
$params = [
];
$this->CRUD->delete($id, $params);
if ($this->IndexFilter->isRest()) {
return $this->restResponsePayload;
}
}
2022-05-04 00:01:02 +02:00
public function view($id)
{
$this->CRUD->view($id, [
]);
if ($this->IndexFilter->isRest()) {
return $this->restResponsePayload;
}
$this->set('id', $id);
$this->set('menuData', array('menuList' => 'workflows', 'menuItem' => 'view'));
}
public function editor($trigger_id)
{
$modules = $this->Workflow->getModulesByType();
$trigger_ids = Hash::extract($modules['blocks_trigger'], '{n}.id');
if (!in_array($trigger_id, $trigger_ids)) {
return $this->__getFailResponseBasedOnContext(
[__('Unkown trigger %s', $trigger_id)],
null,
'add',
$trigger_id,
['controller' => 'workflows', 'action' => 'triggers']
);
}
$workflow = $this->Workflow->fetchWorkflowByTrigger($trigger_id, false);
if (empty($workflow)) { // Workflow do not exists yet. Create it.
$this->Workflow->create();
$savedWorkflow = $this->Workflow->save([
'name' => sprintf('Workflow for trigger %s', $trigger_id),
'trigger_id' => $trigger_id,
]);
if (empty($savedWorkflow)) {
return $this->__getFailResponseBasedOnContext(
[__('Could not create workflow for trigger %s', $trigger_id), $this->validationErrors],
null,
'add',
$trigger_id,
['controller' => 'workflows', 'action' => 'editor']
);
}
$workflow = $savedWorkflow;
}
$modules = $this->Workflow->attachNotificationToModules($modules, $workflow);
$this->set('selectedWorkflow', $workflow);
2022-05-04 00:01:02 +02:00
$this->set('modules', $modules);
}
public function triggers()
{
$triggers = $this->Workflow->getModulesByType('trigger');
$triggers = $this->Workflow->attachWorkflowToTriggers($triggers);
$data = $triggers;
if ($this->_isRest()) {
return $this->RestResponse->viewData($data, $this->response->type());
}
$this->set('data', $data);
$this->set('menuData', ['menuList' => 'workflows', 'menuItem' => 'index_trigger']);
}
public function moduleIndex()
{
$modules = $this->Workflow->getModulesByType();
$this->Module = ClassRegistry::init('Module');
$mispModules = $this->Module->getModules('Action');
$this->set('module_service_error', !is_array($mispModules));
$filters = $this->IndexFilter->harvestParameters(['type']);
$moduleType = $filters['type'] ?? 'action';
if ($moduleType == 'all') {
$data = array_merge(
$modules["blocks_action"],
$modules["blocks_logic"]
);
} else {
$data = $modules["blocks_{$moduleType}"];
}
if ($this->_isRest()) {
return $this->RestResponse->viewData($data, $this->response->type());
}
$this->set('data', $data);
$this->set('indexType', $moduleType);
$this->set('menuData', ['menuList' => 'workflows', 'menuItem' => 'index_module']);
}
public function moduleView($module_id)
{
$module = $this->Workflow->getModuleByID($module_id);
if (empty($module)) {
throw new NotFoundException(__('Invalid trigger ID'));
}
$is_trigger = $module['module_type'] == 'trigger';
if ($is_trigger) {
$module = $this->Workflow->attachWorkflowToTriggers([$module])[0];
}
if ($this->_isRest()) {
return $this->RestResponse->viewData($module, $this->response->type());
}
$this->set('data', $module);
$this->set('menuData', ['menuList' => 'workflows', 'menuItem' => 'view_module']);
}
public function toggleModule($module_id, $enabled, $is_trigger=false)
{
$this->request->allowMethod(['post', 'put']);
$saved = $this->Workflow->toggleModule($module_id, $enabled, $is_trigger);
if ($saved) {
return $this->__getSuccessResponseBasedOnContext(
__('%s module %s', ($enabled ? 'Enabled' : 'Disabled'), $module_id),
null,
'toggle_module',
$module_id,
['action' => (!empty($is_trigger) ? 'triggers' : 'moduleIndex')]
);
} else {
return $this->__getFailResponseBasedOnContext(
__('Could not %s module %s', ($enabled ? 'Enabled' : 'Disabled'), $module_id),
null,
'toggle_module',
$module_id,
['action' => (!empty($is_trigger) ? 'triggers' : 'moduleIndex')]
);
}
}
2022-05-04 00:01:02 +02:00
private function __getSuccessResponseBasedOnContext($message, $data = null, $action = '', $id = false, $redirect = array())
{
if ($this->_isRest()) {
if (!is_null($data)) {
return $this->RestResponse->viewData($data, $this->response->type());
} else {
return $this->RestResponse->saveSuccessResponse('Workflow', $action, $id, false, $message);
2022-05-04 00:01:02 +02:00
}
} elseif ($this->request->is('ajax')) {
return $this->RestResponse->saveSuccessResponse('Workflow', $action, $id, false, $message, $data);
2022-05-04 00:01:02 +02:00
} else {
$this->Flash->success($message);
$this->redirect($redirect);
}
return;
}
2022-05-04 00:01:02 +02:00
private function __getFailResponseBasedOnContext($message, $data = null, $action = '', $id = false, $redirect = array())
{
if (is_array($message)) {
$message = implode(', ', $message);
}
if ($this->_isRest()) {
if ($data !== null) {
return $this->RestResponse->viewData($data, $this->response->type());
} else {
return $this->RestResponse->saveFailResponse('Workflow', $action, $id, $message);
2022-05-04 00:01:02 +02:00
}
} elseif ($this->request->is('ajax')) {
return $this->RestResponse->saveFailResponse('Workflow', $action, $id, $message, false, $data);
2022-05-04 00:01:02 +02:00
} else {
$this->Flash->error($message);
$this->redirect($redirect);
2022-05-04 00:01:02 +02:00
}
}
private function __applyDataFromSavedWorkflow($newWorkflow, $savedWorkflow)
{
if (!isset($newReport['Workflow'])) {
$newReport = ['Workflow' => $newWorkflow];
}
$ignoreFieldList = ['id', 'uuid'];
foreach (Workflow::CAPTURE_FIELDS as $field) {
if (!in_array($field, $ignoreFieldList) && isset($newWorkflow['Workflow'][$field])) {
$savedWorkflow['Workflow'][$field] = $newWorkflow['Workflow'][$field];
}
}
return $savedWorkflow;
}
public function hasAcyclicGraph()
{
$this->request->allowMethod(['post']);
$graphData = $this->request->data;
$cycles = [];
$isAcyclic = $this->Workflow->workflowGraphTool->isAcyclic($graphData, $cycles);
$data = [
'is_acyclic' => $isAcyclic,
'cycles' => $cycles,
];
return $this->RestResponse->viewData($data, 'json');
}
}