2022-06-22 09:46:57 +02:00
|
|
|
<?php
|
|
|
|
App::uses('AppModel', 'Model');
|
2022-07-19 11:50:42 +02:00
|
|
|
App::uses('Folder', 'Utility');
|
2022-06-22 09:46:57 +02:00
|
|
|
|
2022-06-24 17:09:12 +02:00
|
|
|
class WorkflowBlueprint extends AppModel
|
2022-06-22 09:46:57 +02:00
|
|
|
{
|
2022-07-19 11:50:42 +02:00
|
|
|
const REPOSITORY_PATH = APP . 'files' . DS . 'misp-workflow-blueprints' . DS . 'blueprints';
|
2022-06-22 09:46:57 +02:00
|
|
|
public $recursive = -1;
|
|
|
|
|
|
|
|
public $actsAs = [
|
|
|
|
'AuditLog',
|
|
|
|
'Containable',
|
2022-07-05 11:19:18 +02:00
|
|
|
'SysLogLogable.SysLogLogable' => [
|
2022-07-05 15:50:54 +02:00
|
|
|
'roleModel' => 'Role',
|
|
|
|
'roleKey' => 'role_id',
|
|
|
|
'change' => 'full'
|
2022-07-05 11:19:18 +02:00
|
|
|
],
|
2022-06-22 09:46:57 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
public $validate = [
|
2022-10-10 22:26:08 +02:00
|
|
|
'name' => 'stringNotEmpty',
|
2022-06-22 09:46:57 +02:00
|
|
|
'value' => [
|
|
|
|
'stringNotEmpty' => [
|
|
|
|
'rule' => ['stringNotEmpty']
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'uuid' => [
|
|
|
|
'uuid' => [
|
|
|
|
'rule' => 'uuid',
|
|
|
|
'message' => 'Please provide a valid RFC 4122 UUID'
|
|
|
|
],
|
|
|
|
'unique' => [
|
|
|
|
'rule' => 'isUnique',
|
|
|
|
'message' => 'The UUID provided is not unique',
|
|
|
|
'required' => 'create'
|
|
|
|
]
|
|
|
|
],
|
|
|
|
];
|
|
|
|
|
|
|
|
const CAPTURE_FIELDS = ['name', 'description', 'timestamp', 'data'];
|
|
|
|
|
|
|
|
public function beforeValidate($options = array())
|
|
|
|
{
|
|
|
|
parent::beforeValidate();
|
2022-06-24 17:09:12 +02:00
|
|
|
if (empty($this->data['WorkflowBlueprint']['uuid'])) {
|
|
|
|
$this->data['WorkflowBlueprint']['uuid'] = CakeText::uuid();
|
2022-06-22 09:46:57 +02:00
|
|
|
} else {
|
2022-06-24 17:09:12 +02:00
|
|
|
$this->data['WorkflowBlueprint']['uuid'] = strtolower($this->data['WorkflowBlueprint']['uuid']);
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
2022-06-24 17:09:12 +02:00
|
|
|
if (empty($this->data['WorkflowBlueprint']['data'])) {
|
|
|
|
$this->data['WorkflowBlueprint']['data'] = [];
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
2022-06-24 17:09:12 +02:00
|
|
|
if (empty($this->data['WorkflowBlueprint']['timestamp'])) {
|
|
|
|
$this->data['WorkflowBlueprint']['timestamp'] = time();
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function afterFind($results, $primary = false)
|
|
|
|
{
|
|
|
|
foreach ($results as $k => $result) {
|
2022-06-24 17:09:12 +02:00
|
|
|
if (empty($result['WorkflowBlueprint']['data'])) {
|
|
|
|
$result['WorkflowBlueprint']['data'] = '{}';
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
2022-06-24 17:09:12 +02:00
|
|
|
$results[$k]['WorkflowBlueprint']['data'] = JsonTool::decode($result['WorkflowBlueprint']['data']);
|
2022-08-24 09:14:17 +02:00
|
|
|
$blueprint = $this->attachModuleDataToBlueprint($results[$k]);
|
2022-07-13 14:43:13 +02:00
|
|
|
if (!empty($results[$k]['WorkflowBlueprint']['data'])) {
|
2022-08-24 09:14:17 +02:00
|
|
|
$results[$k]['WorkflowBlueprint']['mermaid'] = $this->getMermaidForData($blueprint['WorkflowBlueprint']['data']);
|
2022-07-13 14:43:13 +02:00
|
|
|
}
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
|
|
|
return $results;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function beforeSave($options = [])
|
|
|
|
{
|
2022-06-24 17:09:12 +02:00
|
|
|
if (is_array($this->data['WorkflowBlueprint']['data'])) {
|
|
|
|
$this->data['WorkflowBlueprint']['data'] = JsonTool::encode($this->data['WorkflowBlueprint']['data']);
|
2022-06-22 11:57:43 +02:00
|
|
|
}
|
2022-06-22 09:46:57 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-07-29 08:33:59 +02:00
|
|
|
public function attachModuleDataToBlueprint(array $blueprint)
|
|
|
|
{
|
|
|
|
$this->Workflow = ClassRegistry::init('Workflow');
|
|
|
|
foreach ($blueprint['WorkflowBlueprint']['data'] as $i => $node) {
|
|
|
|
$module = $this->Workflow->getModuleConfigByType($node['data']['module_type'], $node['data']['id']);
|
|
|
|
$blueprint['WorkflowBlueprint']['data'][$i]['data']['module_data'] = $module;
|
|
|
|
}
|
|
|
|
return $blueprint;
|
|
|
|
}
|
|
|
|
|
2022-07-19 11:50:42 +02:00
|
|
|
/**
|
|
|
|
* __readBlueprintsFromRepo Reads blueprints from the misp-workflow-blueprints repository
|
|
|
|
*
|
|
|
|
* @return array
|
2022-10-10 19:47:40 +02:00
|
|
|
* @throws Exception
|
2022-07-19 11:50:42 +02:00
|
|
|
*/
|
|
|
|
private function __readBlueprintsFromRepo(): array
|
2022-06-22 09:46:57 +02:00
|
|
|
{
|
2022-07-19 11:50:42 +02:00
|
|
|
$dir = new Folder(self::REPOSITORY_PATH);
|
|
|
|
$files = $dir->find('.*\.json');
|
|
|
|
$blueprints = [];
|
|
|
|
foreach ($files as $file) {
|
2022-08-04 08:14:51 +02:00
|
|
|
$blueprints[] = FileAccessTool::readJsonFromFile($dir->pwd() . DS . $file);
|
2022-07-19 11:50:42 +02:00
|
|
|
}
|
|
|
|
return $blueprints;
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
|
|
|
|
2022-07-19 11:50:42 +02:00
|
|
|
/**
|
|
|
|
* update Update the blueprint using the default repository
|
|
|
|
*
|
|
|
|
* @param boolean $force
|
|
|
|
* @return void
|
2022-10-10 22:26:08 +02:00
|
|
|
* @throws Exception
|
2022-07-19 11:50:42 +02:00
|
|
|
*/
|
|
|
|
public function update($force=false)
|
2022-06-22 09:46:57 +02:00
|
|
|
{
|
2022-07-19 11:50:42 +02:00
|
|
|
$blueprints_from_repo = $this->__readBlueprintsFromRepo();
|
|
|
|
if (empty($blueprints_from_repo)) {
|
|
|
|
throw new NotFoundException(__('Default blueprints could not be loaded or `%s` folder is empty', self::REPOSITORY_PATH));
|
|
|
|
}
|
2022-07-25 14:09:29 +02:00
|
|
|
$existing_blueprints = $this->find('all', [
|
2022-07-19 11:50:42 +02:00
|
|
|
'recursive' => -1
|
2022-07-25 14:09:29 +02:00
|
|
|
]);
|
2022-07-19 11:50:42 +02:00
|
|
|
$existing_blueprints_by_uuid = Hash::combine($existing_blueprints, '{n}.WorkflowBlueprint.uuid', '{n}.WorkflowBlueprint');
|
|
|
|
foreach ($blueprints_from_repo as $blueprint_from_repo) {
|
|
|
|
$blueprint_from_repo = $blueprint_from_repo['WorkflowBlueprint'];
|
2022-08-04 08:17:26 +02:00
|
|
|
$blueprint_from_repo['default'] = true;
|
2022-07-19 11:50:42 +02:00
|
|
|
if (!empty($existing_blueprints_by_uuid[$blueprint_from_repo['uuid']])) {
|
|
|
|
$existing_blueprint = $existing_blueprints_by_uuid[$blueprint_from_repo['uuid']];
|
|
|
|
if ($force || $blueprint_from_repo['timestamp'] > $existing_blueprint['timestamp']) {
|
|
|
|
$blueprint_from_repo['id'] = $existing_blueprint['id'];
|
|
|
|
$this->save($blueprint_from_repo);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$this->create();
|
|
|
|
$this->save($blueprint_from_repo);
|
2022-06-22 09:46:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-07-19 11:50:42 +02:00
|
|
|
|
2022-07-25 14:09:29 +02:00
|
|
|
public function getMermaidForData($workflowBlueprintData)
|
2022-07-13 14:43:13 +02:00
|
|
|
{
|
|
|
|
App::uses('MermaidFlowchartTool', 'Tools');
|
|
|
|
$mermaid = MermaidFlowchartTool::mermaid($workflowBlueprintData);
|
|
|
|
return $mermaid;
|
|
|
|
}
|
2022-07-25 14:09:29 +02:00
|
|
|
|
|
|
|
public function getDotNotation($id)
|
|
|
|
{
|
|
|
|
App::uses('GraphvizDOTTool', 'Tools');
|
|
|
|
$blueprint = $this->find('first', [
|
|
|
|
'conditions' => ['id' => $id],
|
|
|
|
'recursive' => -1,
|
|
|
|
]);
|
|
|
|
$dot = GraphvizDOTTool::dot($blueprint['WorkflowBlueprint']['data']);
|
|
|
|
return $dot;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getMermaid($id)
|
|
|
|
{
|
|
|
|
App::uses('MermaidFlowchartTool', 'Tools');
|
|
|
|
$blueprint = $this->find('first', [
|
|
|
|
'conditions' => ['id' => $id],
|
|
|
|
'recursive' => -1,
|
|
|
|
]);
|
|
|
|
$mermaid = MermaidFlowchartTool::mermaid($blueprint['WorkflowBlueprint']['data']);
|
|
|
|
return $mermaid;
|
|
|
|
}
|
2022-07-25 13:41:13 +02:00
|
|
|
}
|