mirror of https://github.com/MISP/MISP
chg: [workflow] Moved directory of custom modules in `Lib` folder
parent
aef257b4f7
commit
a220cac1a5
|
@ -157,7 +157,7 @@ class WorkflowsController extends AppController
|
|||
$moduleType = $filters['type'] ?? 'action';
|
||||
$actionType = $filters['actiontype'] ?? 'all';
|
||||
$enabledState = $filters['enabled'] ?? false;
|
||||
if ($moduleType == 'all') {
|
||||
if ($moduleType == 'all' || $moduleType == 'custom') {
|
||||
$data = array_merge(
|
||||
$modules["blocks_action"],
|
||||
$modules["blocks_logic"]
|
||||
|
@ -173,6 +173,10 @@ class WorkflowsController extends AppController
|
|||
$data = array_filter($data, function ($module) {
|
||||
return !empty($module['is_blocking']);
|
||||
});
|
||||
} else if ($moduleType == 'custom') {
|
||||
$data = array_filter($data, function ($module) {
|
||||
return !empty($module['is_custom']);
|
||||
});
|
||||
}
|
||||
if ($enabledState !== false) {
|
||||
$moduleType = !empty($enabledState) ? 'enabled' : 'disabled';
|
||||
|
|
|
@ -129,11 +129,14 @@ class GraphWalker
|
|||
{
|
||||
$outputs = ($node['outputs'] ?? []);
|
||||
if ($node['data']['id'] == 'if') {
|
||||
$useThenBranch = $this->_evaluateIFCondition($node, $roamingData);
|
||||
return $useThenBranch ? ['output_1' => $outputs['output_1']] : ['output_2' => $outputs['output_2']];
|
||||
$useFirstOutput = $this->_evaluateIFCondition($node, $roamingData);
|
||||
return $useFirstOutput ? ['output_1' => $outputs['output_1']] : ['output_2' => $outputs['output_2']];
|
||||
} else if ($node['data']['id'] == 'parallel-task') {
|
||||
$this->_evaluateParallelTask($node, $roamingData, $outputs['output_1']);
|
||||
return ['output_1' => []];
|
||||
} else {
|
||||
$useFirstOutput = $this->_evaluateCustomLogicCondition($node, $roamingData);
|
||||
return $useFirstOutput ? ['output_1' => $outputs['output_1']] : ['output_2' => $outputs['output_2']];
|
||||
}
|
||||
return $outputs;
|
||||
}
|
||||
|
@ -144,6 +147,12 @@ class GraphWalker
|
|||
return $result;
|
||||
}
|
||||
|
||||
private function _evaluateCustomLogicCondition($node, WorkflowRoamingData $roamingData): bool
|
||||
{
|
||||
$result = $this->WorkflowModel->__executeNode($node, $roamingData);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function _evaluateParallelTask($parallel_node, WorkflowRoamingData $roamingData, array $connections)
|
||||
{
|
||||
foreach ($connections['connections'] as $connection) {
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
include_once APP . 'Model/WorkflowModules/WorkflowBaseModule.php';
|
||||
|
||||
class Module_blueprint_action_module extends WorkflowBaseModule
|
||||
{
|
||||
public $is_blocking = false;
|
||||
public $disabled = true;
|
||||
public $id = 'blueprint-action-module';
|
||||
public $name = 'Blueprint action module';
|
||||
public $description = 'Lorem ipsum dolor, sit amet consectetur adipisicing elit.';
|
||||
public $icon = 'shapes';
|
||||
public $inputs = 1;
|
||||
public $outputs = 1;
|
||||
public $params = [];
|
||||
|
||||
public function exec(array $node, WorkflowRoamingData $roamingData, array &$errors = []): bool
|
||||
{
|
||||
parent::exec($node, $roamingData, $errors);
|
||||
// If $this->is_blocking == true, returning `false` will stop the execution.
|
||||
$errors[] = __('Execution stopped');
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
include_once APP . 'Model/WorkflowModules/WorkflowBaseModule.php';
|
||||
|
||||
class Module_blueprint_logic_module extends WorkflowBaseLogicModule
|
||||
{
|
||||
public $disabled = true;
|
||||
public $id = 'blueprint-logic-module';
|
||||
public $name = 'Blueprint logic module';
|
||||
public $description = 'Lorem ipsum dolor, sit amet consectetur adipisicing elit.';
|
||||
public $icon = 'shapes';
|
||||
public $inputs = 1;
|
||||
public $outputs = 2;
|
||||
public $params = [];
|
||||
|
||||
public function exec(array $node, WorkflowRoamingData $roamingData, array &$errors = []): bool
|
||||
{
|
||||
parent::exec($node, $roamingData, $errors);
|
||||
$params = $this->getParamsWithValues($node);
|
||||
$data = $roamingData->getData();
|
||||
// Returning true will make the execution flow take the first output of this module. Otherwise, the second output will be used.
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -63,6 +63,7 @@ class Workflow extends AppModel
|
|||
const CAPTURE_FIELDS = ['name', 'description', 'timestamp', 'data'];
|
||||
|
||||
const MODULE_ROOT_PATH = APP . 'Model/WorkflowModules/';
|
||||
const CUSTOM_MODULE_ROOT_PATH = APP . 'Lib/WorkflowModules/';
|
||||
const REDIS_KEY_WORKFLOW_NAMESPACE = 'workflow';
|
||||
const REDIS_KEY_WORKFLOW_PER_TRIGGER = 'workflow:workflow_list:%s';
|
||||
const REDIS_KEY_TRIGGER_PER_WORKFLOW = 'workflow:trigger_list:%s';
|
||||
|
@ -149,7 +150,7 @@ class Workflow extends AppModel
|
|||
}
|
||||
|
||||
$filename = sprintf('Module_%s.php', preg_replace('/[^a-zA-Z0-9_]/', '_', Inflector::underscore($trigger_id)));
|
||||
$module_config = $this->__getClassFromModuleFiles('trigger', [$filename])['classConfigs'];
|
||||
$module_config = $this->__getClassFromModuleFiles('trigger', [$filename], false)['classConfigs'];
|
||||
return empty($module_config['disabled']);
|
||||
}
|
||||
|
||||
|
@ -590,13 +591,26 @@ class Workflow extends AppModel
|
|||
}
|
||||
$phpModuleFiles = Workflow::__listPHPModuleFiles();
|
||||
foreach ($phpModuleFiles as $type => $files) {
|
||||
$classModuleFromFiles = $this->__getClassFromModuleFiles($type, $files);
|
||||
if ($type == 'custom') {
|
||||
continue;
|
||||
}
|
||||
$classModuleFromFiles = $this->__getClassFromModuleFiles($type, $files, false);
|
||||
foreach ($classModuleFromFiles['classConfigs'] as $i => $config) {
|
||||
$classModuleFromFiles['classConfigs'][$i]['module_type'] = $type;
|
||||
}
|
||||
$this->loaded_modules[$type] = $classModuleFromFiles['classConfigs'];
|
||||
$this->loaded_classes[$type] = $classModuleFromFiles['instancedClasses'];
|
||||
}
|
||||
// Load custom PHP modules from Lib
|
||||
foreach ($phpModuleFiles['custom'] as $type => $files) {
|
||||
$classModuleFromFiles = $this->__getClassFromModuleFiles($type, $files, true);
|
||||
foreach ($classModuleFromFiles['classConfigs'] as $i => $config) {
|
||||
$classModuleFromFiles['classConfigs'][$i]['module_type'] = $type;
|
||||
}
|
||||
$this->loaded_modules[$type] = array_merge($this->loaded_modules[$type], $classModuleFromFiles['classConfigs']);
|
||||
$this->loaded_classes[$type] = array_merge($this->loaded_classes[$type], $classModuleFromFiles['instancedClasses']);
|
||||
}
|
||||
// Load module from misp-module service
|
||||
$modules_from_service = $this->__getModulesFromModuleService() ?? [];
|
||||
$misp_module_class = $this->__getClassForMispModule($modules_from_service);
|
||||
$misp_module_configs = [];
|
||||
|
@ -703,24 +717,21 @@ class Workflow extends AppModel
|
|||
$folder = new Folder(Workflow::MODULE_ROOT_PATH . $dir);
|
||||
$filesInFolder = $folder->find('.*\.php', true);
|
||||
$files[$dir] = array_diff($filesInFolder, ['..', '.']);
|
||||
if ($dir == 'action') { // No custom module for the triggers
|
||||
$customFolder = new Folder(Workflow::MODULE_ROOT_PATH . $dir . '/Custom');
|
||||
if ($dir == 'action' || $dir == 'logic') { // No custom module for the triggers
|
||||
$customFolder = new Folder(Workflow::CUSTOM_MODULE_ROOT_PATH . $dir);
|
||||
$filesInCustomFolder = $customFolder->find('.*\.php', true);
|
||||
$filesInCustomFolder = array_map(function($file) {
|
||||
return 'Custom/' . $file;
|
||||
}, $filesInCustomFolder);
|
||||
$files[$dir] = array_merge($filesInFolder, array_diff($filesInCustomFolder, ['..', '.']));
|
||||
$files['custom'][$dir] = array_diff($filesInCustomFolder, ['..', '.']);
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
private function __getClassFromModuleFiles($type, $files)
|
||||
private function __getClassFromModuleFiles($type, $files, $isCustom=false)
|
||||
{
|
||||
$instancedClasses = [];
|
||||
$classConfigs = [];
|
||||
foreach ($files as $filename) {
|
||||
$filepath = sprintf('%s%s/%s', Workflow::MODULE_ROOT_PATH, $type, $filename);
|
||||
$filepath = sprintf('%s%s/%s', (!empty($isCustom) ? Workflow::CUSTOM_MODULE_ROOT_PATH : Workflow::MODULE_ROOT_PATH), $type, $filename);
|
||||
$instancedClass = $this->__getClassFromModuleFile($filepath);
|
||||
if (is_string($instancedClass)) {
|
||||
$this->__logLoadingError($filename, $instancedClass);
|
||||
|
@ -731,6 +742,10 @@ class Workflow extends AppModel
|
|||
}
|
||||
$classConfigs[$instancedClass->id] = $instancedClass->getConfig();
|
||||
$instancedClasses[$instancedClass->id] = $instancedClass;
|
||||
if (!empty($isCustom)) {
|
||||
$classConfigs[$instancedClass->id]['is_custom'] = true;
|
||||
$instancedClasses[$instancedClass->id]->is_custom = true;
|
||||
}
|
||||
}
|
||||
return [
|
||||
'classConfigs' => $classConfigs,
|
||||
|
|
|
@ -3,6 +3,7 @@ class WorkflowBaseModule
|
|||
{
|
||||
public $is_misp_module = false;
|
||||
public $is_blocking = false;
|
||||
public $is_custom = false;
|
||||
public $id = 'to-override';
|
||||
public $name = 'to-override';
|
||||
public $version = '0.1';
|
||||
|
@ -175,4 +176,13 @@ class WorkflowBaseModule
|
|||
class WorkflowBaseTriggerModule extends WorkflowBaseModule
|
||||
{
|
||||
public $blocking = false;
|
||||
public $inputs = 0;
|
||||
public $outputs = 1;
|
||||
}
|
||||
|
||||
class WorkflowBaseLogicModule extends WorkflowBaseModule
|
||||
{
|
||||
public $blocking = false;
|
||||
public $inputs = 1;
|
||||
public $outputs = 2;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
<?php
|
||||
include_once APP . 'Model/WorkflowModules/WorkflowBaseModule.php';
|
||||
|
||||
class Module_custom_action extends WorkflowBaseModule
|
||||
{
|
||||
public $id = 'custom-action';
|
||||
public $name = 'User-defined Module';
|
||||
public $description = 'Lorem ipsum dolor, sit amet consectetur adipisicing elit.';
|
||||
public $icon = 'hand-point-up';
|
||||
public $inputs = 1;
|
||||
public $outputs = 0;
|
||||
public $params = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
}
|
|
@ -38,8 +38,16 @@
|
|||
'sort' => 'is_misp_module',
|
||||
'data_path' => 'is_misp_module',
|
||||
'element' => 'boolean',
|
||||
'requirement' => $indexType == 'action',
|
||||
'colors' => true,
|
||||
'class' => 'short',
|
||||
],
|
||||
[
|
||||
'name' => __('Custom'),
|
||||
'sort' => 'is_custom',
|
||||
'data_path' => 'is_custom',
|
||||
'element' => 'boolean',
|
||||
'colors' => true,
|
||||
'class' => 'short',
|
||||
],
|
||||
[
|
||||
'name' => __('Enabled'),
|
||||
|
@ -86,11 +94,26 @@
|
|||
'text' => __('misp-module'),
|
||||
'active' => $indexType === 'action' && $actionType === 'mispmodule',
|
||||
],
|
||||
[
|
||||
'url' => $baseurl . '/workflows/moduleIndex/type:custom',
|
||||
'text' => __('Custom'),
|
||||
'active' => $indexType === 'custom',
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => 'simple',
|
||||
'children' => [
|
||||
[
|
||||
'url' => $baseurl . '/workflows/moduleIndex/actiontype:blocking',
|
||||
'text' => __('Blocking'),
|
||||
'active' => $indexType === 'action' && $actionType === 'blocking',
|
||||
],
|
||||
]
|
||||
],
|
||||
[
|
||||
'type' => 'simple',
|
||||
'children' => [
|
||||
[
|
||||
'url' => $baseurl . '/workflows/moduleIndex/type:all/enabled:1',
|
||||
'text' => __('Enabled'),
|
||||
|
|
Loading…
Reference in New Issue