2016-05-10 10:31:56 +02:00
< ? php
App :: uses ( 'AppModel' , 'Model' );
2021-10-17 15:24:54 +02:00
App :: uses ( 'JsonTool' , 'Tools' );
2016-05-10 10:31:56 +02:00
2018-07-19 11:48:22 +02:00
class Module extends AppModel
{
public $useTable = false ;
private $__validTypes = array (
'Enrichment' => array ( 'hover' , 'expansion' ),
'Import' => array ( 'import' ),
'Export' => array ( 'export' ),
2022-05-04 01:23:13 +02:00
'Action' => array ( 'action' ),
2018-07-19 11:48:22 +02:00
'Cortex' => array ( 'cortex' )
);
private $__typeToFamily = array (
'Import' => 'Import' ,
'Export' => 'Export' ,
2022-05-04 01:23:13 +02:00
'Action' => 'Action' ,
2018-07-19 11:48:22 +02:00
'hover' => 'Enrichment' ,
'expansion' => 'Enrichment' ,
'Cortex' => 'Cortex'
);
public $configTypes = array (
'IP' => array (
'validation' => 'validateIPField' ,
'field' => 'text' ,
'class' => 'input-xxlarge'
),
'String' => array (
'validation' => 'validateStringField' ,
'field' => 'text' ,
'class' => 'input-xxlarge'
),
'Integer' => array (
'validation' => 'validateIntegerField' ,
'field' => 'number' ,
),
'Boolean' => array (
'validation' => 'validateBooleanField' ,
'field' => 'checkbox'
),
'Select' => array (
'validation' => 'validateSelectField' ,
'field' => 'select'
)
);
public function validateIPField ( $value )
{
if ( ! filter_var ( $value , FILTER_VALIDATE_IP ) === false ) {
return 'Value is not a valid IP.' ;
}
return true ;
}
public function validateStringField ( $value )
{
if ( ! empty ( $value )) {
return true ;
}
return 'Field cannot be empty.' ;
}
public function validateIntegerField ( $value )
{
if ( is_numeric ( $value ) && is_int ( intval ( $value ))) {
return true ;
}
return 'Value is not an integer.' ;
}
public function validateBooleanField ( $value )
{
if ( $value == true || $value == false ) {
return true ;
}
return 'Value has to be a boolean.' ;
}
public function validateSelectField ( $value )
{
return true ;
}
2020-10-18 15:36:03 +02:00
/**
* @ param string $moduleFamily
* @ param bool $throwException
* @ return array [] | string
* @ throws JsonException
*/
public function getModules ( $moduleFamily = 'Enrichment' , $throwException = false )
2018-07-19 11:48:22 +02:00
{
2020-10-22 19:42:47 +02:00
try {
// Wait just one second to not block loading pages when modules are not reachable
return $this -> sendRequest ( '/modules' , 1 , null , $moduleFamily );
} catch ( Exception $e ) {
if ( $throwException ) {
throw $e ;
}
2018-07-19 11:48:22 +02:00
return 'Module service not reachable.' ;
}
}
public function getEnabledModules ( $user , $type = false , $moduleFamily = 'Enrichment' )
{
2020-10-22 12:54:23 +02:00
$modules = $this -> getModules ( $moduleFamily );
2018-07-19 11:48:22 +02:00
if ( is_array ( $modules )) {
2020-10-18 15:36:03 +02:00
foreach ( $modules as $k => $module ) {
2018-07-19 11:48:22 +02:00
if ( ! Configure :: read ( 'Plugin.' . $moduleFamily . '_' . $module [ 'name' ] . '_enabled' ) || ( $type && ! in_array ( strtolower ( $type ), $module [ 'meta' ][ 'module-type' ]))) {
2020-10-18 15:36:03 +02:00
unset ( $modules [ $k ]);
2018-07-19 11:48:22 +02:00
continue ;
}
if (
! $user [ 'Role' ][ 'perm_site_admin' ] &&
Configure :: read ( 'Plugin.' . $moduleFamily . '_' . $module [ 'name' ] . '_restrict' ) &&
Configure :: read ( 'Plugin.' . $moduleFamily . '_' . $module [ 'name' ] . '_restrict' ) != $user [ 'org_id' ]
) {
2020-10-18 15:36:03 +02:00
unset ( $modules [ $k ]);
2018-07-19 11:48:22 +02:00
}
}
} else {
return 'The modules system reports that it found no suitable modules.' ;
}
2020-10-18 15:36:03 +02:00
if ( empty ( $modules )) {
return [];
2018-07-19 11:48:22 +02:00
}
2020-10-18 15:36:03 +02:00
$output = [ 'modules' => array_values ( $modules )];
foreach ( $modules as $temp ) {
2018-07-19 11:48:22 +02:00
if ( isset ( $temp [ 'meta' ][ 'module-type' ]) && in_array ( 'import' , $temp [ 'meta' ][ 'module-type' ])) {
2020-10-18 15:36:03 +02:00
$output [ 'Import' ] = $temp [ 'name' ];
2018-07-19 11:48:22 +02:00
} elseif ( isset ( $temp [ 'meta' ][ 'module-type' ]) && in_array ( 'export' , $temp [ 'meta' ][ 'module-type' ])) {
2020-10-18 15:36:03 +02:00
$output [ 'Export' ] = $temp [ 'name' ];
2022-05-04 01:23:13 +02:00
} elseif ( isset ( $temp [ 'meta' ][ 'module-type' ]) && in_array ( 'action' , $temp [ 'meta' ][ 'module-type' ])) {
$output [ 'Action' ] = $temp [ 'name' ];
2018-07-19 11:48:22 +02:00
} else {
foreach ( $temp [ 'mispattributes' ][ 'input' ] as $input ) {
if ( ! isset ( $temp [ 'meta' ][ 'module-type' ]) || ( in_array ( 'expansion' , $temp [ 'meta' ][ 'module-type' ]) || in_array ( 'cortex' , $temp [ 'meta' ][ 'module-type' ]))) {
2020-10-18 15:36:03 +02:00
$output [ 'types' ][ $input ][] = $temp [ 'name' ];
2018-07-19 11:48:22 +02:00
}
if ( isset ( $temp [ 'meta' ][ 'module-type' ]) && in_array ( 'hover' , $temp [ 'meta' ][ 'module-type' ])) {
2020-10-18 15:36:03 +02:00
$output [ 'hover_type' ][ $input ][] = $temp [ 'name' ];
2018-07-19 11:48:22 +02:00
}
}
}
}
2020-10-18 15:36:03 +02:00
return $output ;
2018-07-19 11:48:22 +02:00
}
2020-10-06 17:59:02 +02:00
/**
* @ param string $name
* @ param string $type
* @ return array | string
*/
2018-07-19 11:48:22 +02:00
public function getEnabledModule ( $name , $type )
{
2020-10-06 17:59:02 +02:00
if ( ! isset ( $this -> __typeToFamily [ $type ])) {
throw new InvalidArgumentException ( " Invalid type ' $type '. " );
}
2018-07-19 11:48:22 +02:00
$moduleFamily = $this -> __typeToFamily [ $type ];
2020-10-22 12:54:23 +02:00
$modules = $this -> getModules ( $moduleFamily );
2018-07-19 11:48:22 +02:00
if ( ! Configure :: read ( 'Plugin.' . $moduleFamily . '_' . $name . '_enabled' )) {
return 'The requested module is not enabled.' ;
}
if ( is_array ( $modules )) {
2020-10-26 13:45:54 +01:00
foreach ( $modules as $module ) {
2018-07-19 11:48:22 +02:00
if ( $module [ 'name' ] == $name ) {
if ( $type && in_array ( strtolower ( $type ), $module [ 'meta' ][ 'module-type' ])) {
return $module ;
} else {
return 'The requested module is not available for the requested action.' ;
}
}
}
} else {
return $modules ;
}
return 'The modules system reports that it found no suitable modules.' ;
}
private function __getModuleServer ( $moduleFamily = 'Enrichment' )
{
if ( ! Configure :: read ( 'Plugin.' . $moduleFamily . '_services_enable' )) {
return false ;
}
2020-10-06 17:59:02 +02:00
$url = Configure :: read ( 'Plugin.' . $moduleFamily . '_services_url' );
$port = Configure :: read ( 'Plugin.' . $moduleFamily . '_services_port' );
if ( empty ( $url ) || empty ( $port )) {
// Load default values
$this -> Server = ClassRegistry :: init ( 'Server' );
if ( empty ( $url )) {
$url = $this -> Server -> serverSettings [ 'Plugin' ][ $moduleFamily . '_services_url' ][ 'value' ];
}
if ( empty ( $port )) {
$port = $this -> Server -> serverSettings [ 'Plugin' ][ $moduleFamily . '_services_port' ][ 'value' ];
}
}
return " $url : $port " ;
2018-07-19 11:48:22 +02:00
}
2020-10-22 12:58:17 +02:00
/**
2020-10-22 19:42:47 +02:00
* Send request to `/query` module endpoint .
*
* @ param array $postData
2020-10-22 12:58:17 +02:00
* @ param bool $hover
* @ param string $moduleFamily
2020-10-18 15:36:03 +02:00
* @ param bool $throwException
2020-10-22 12:58:17 +02:00
* @ return array | false
2020-10-18 15:36:03 +02:00
* @ throws JsonException
2020-10-22 12:58:17 +02:00
*/
2020-10-22 19:42:47 +02:00
public function queryModuleServer ( array $postData , $hover = false , $moduleFamily = 'Enrichment' , $throwException = false )
2018-07-19 11:48:22 +02:00
{
2020-10-22 19:42:47 +02:00
if ( $hover ) {
$timeout = Configure :: read ( 'Plugin.' . $moduleFamily . '_hover_timeout' ) ? : 5 ;
} else {
$timeout = Configure :: read ( 'Plugin.' . $moduleFamily . '_timeout' ) ? : 10 ;
}
try {
return $this -> sendRequest ( '/query' , $timeout , $postData , $moduleFamily );
} catch ( Exception $e ) {
2020-10-18 15:36:03 +02:00
if ( $throwException ) {
2020-10-22 19:42:47 +02:00
throw $e ;
2020-10-18 15:36:03 +02:00
}
2020-10-22 19:42:47 +02:00
$this -> logException ( 'Failed to query module ' . $moduleFamily , $e );
2018-07-19 11:48:22 +02:00
return false ;
}
2020-10-22 19:42:47 +02:00
}
/**
* Low - level way how to send request to module .
*
* @ param string $uri
* @ param int $timeout
* @ param array | null $postData
* @ param string $moduleFamily
* @ return array
2021-10-17 15:24:54 +02:00
* @ throws HttpSocketJsonException
* @ throws Exception
2020-10-22 19:42:47 +02:00
*/
public function sendRequest ( $uri , $timeout , $postData = null , $moduleFamily = 'Enrichment' )
{
2021-10-17 15:24:54 +02:00
$serverUrl = $this -> __getModuleServer ( $moduleFamily );
if ( ! $serverUrl ) {
2020-10-22 19:42:47 +02:00
throw new Exception ( " Module type $moduleFamily is not enabled. " );
2018-07-19 11:48:22 +02:00
}
2021-10-17 15:24:54 +02:00
App :: uses ( 'HttpSocketExtended' , 'Tools' );
$httpSocketSetting = [ 'timeout' => $timeout ];
2018-07-19 11:48:22 +02:00
$sslSettings = array ( 'ssl_verify_peer' , 'ssl_verify_host' , 'ssl_allow_self_signed' , 'ssl_verify_peer' , 'ssl_cafile' );
foreach ( $sslSettings as $sslSetting ) {
2021-10-17 15:24:54 +02:00
$value = Configure :: read ( 'Plugin.' . $moduleFamily . '_' . $sslSetting );
if ( $value && $value !== '' ) {
$httpSocketSetting [ $sslSetting ] = $value ;
2018-07-19 11:48:22 +02:00
}
}
2021-10-17 15:24:54 +02:00
$httpSocket = new HttpSocketExtended ( $httpSocketSetting );
$request = [];
if ( $moduleFamily === 'Cortex' ) {
2018-07-19 11:48:22 +02:00
if ( ! empty ( Configure :: read ( 'Plugin.' . $moduleFamily . '_authkey' ))) {
$request [ 'header' ][ 'Authorization' ] = 'Bearer ' . Configure :: read ( 'Plugin.' . $moduleFamily . '_authkey' );
}
}
2020-10-22 19:42:47 +02:00
if ( $postData ) {
if ( ! is_array ( $postData )) {
throw new InvalidArgumentException ( " Post data must be array, " . gettype ( $postData ) . " given. " );
2018-07-19 11:48:22 +02:00
}
2021-10-17 15:24:54 +02:00
$post = JsonTool :: encode ( $postData );
$request [ 'header' ][ 'Content-Type' ] = 'application/json' ;
$response = $httpSocket -> post ( $serverUrl . $uri , $post , $request );
2020-10-22 19:42:47 +02:00
} else {
2021-10-17 15:24:54 +02:00
$response = $httpSocket -> get ( $serverUrl . $uri , false , $request );
2020-10-22 19:42:47 +02:00
}
if ( ! $response -> isOk ()) {
2021-10-17 15:24:54 +02:00
$e = new HttpSocketHttpException ( $response , $serverUrl . $uri );
throw new Exception ( " Failed to get response from ` $moduleFamily ` module " , 0 , $e );
2018-07-19 11:48:22 +02:00
}
2021-10-17 15:24:54 +02:00
return $response -> json ();
2018-07-19 11:48:22 +02:00
}
2020-10-22 13:03:53 +02:00
/**
* @ param string $moduleFamily
* @ return array
2021-10-17 15:24:54 +02:00
* @ throws JsonException
2020-10-22 13:03:53 +02:00
*/
2018-07-19 11:48:22 +02:00
public function getModuleSettings ( $moduleFamily = 'Enrichment' )
{
2020-10-22 12:54:23 +02:00
$modules = $this -> getModules ( $moduleFamily );
2018-07-19 11:48:22 +02:00
$result = array ();
2020-11-01 15:19:57 +01:00
if ( is_array ( $modules )) {
2020-10-18 15:36:03 +02:00
foreach ( $modules as $module ) {
2018-07-19 11:48:22 +02:00
if ( array_intersect ( $this -> __validTypes [ $moduleFamily ], $module [ 'meta' ][ 'module-type' ])) {
2020-10-22 13:03:53 +02:00
$moduleSettings = [
2022-05-04 01:23:13 +02:00
[
'name' => 'enabled' ,
'type' => 'boolean' ,
'description' => empty ( $module [ 'meta' ][ 'description' ]) ? '' : $module [ 'meta' ][ 'description' ]
]
2020-10-22 13:03:53 +02:00
];
2022-05-04 01:23:13 +02:00
if ( $moduleFamily === 'Action' ) {
$moduleSettings [] = [
'name' => 'weight' ,
'type' => 'numeric' ,
'value' => 0 ,
'description' => __ ( 'Set a weight (via an integer) for the module, determining its position in the order of executed modules. Higher values are taken first.' ),
'test' => 'testForNumeric' ,
'null' => true
];
} else {
$moduleSettings [] = [
'name' => 'restrict' ,
'type' => 'orgs' ,
'description' => __ ( 'Restrict the use of this module to an organisation.' )
];
}
2018-07-19 11:48:22 +02:00
if ( isset ( $module [ 'meta' ][ 'config' ])) {
2020-10-22 13:03:53 +02:00
foreach ( $module [ 'meta' ][ 'config' ] as $key => $value ) {
2022-05-04 01:23:13 +02:00
if ( is_array ( $value )) {
$name = is_string ( $key ) ? $key : $value [ 'name' ];
$moduleSettings [] = [
'name' => $name ,
'type' => isset ( $value [ 'type' ]) ? $value [ 'type' ] : 'string' ,
'test' => isset ( $value [ 'test' ]) ? $value [ 'test' ] : null ,
'description' => isset ( $value [ 'description' ]) ? $value [ 'description' ] : null ,
'null' => isset ( $value [ 'null' ]) ? $value [ 'null' ] : null ,
'test' => isset ( $value [ 'test' ]) ? $value [ 'test' ] : null ,
'bigField' => isset ( $value [ 'bigField' ]) ? $value [ 'bigField' ] : false ,
'cli_only' => isset ( $value [ 'cli_only' ]) ? $value [ 'cli_only' ] : false ,
'redacted' => isset ( $value [ 'redacted' ]) ? $value [ 'redacted' ] : false
];
} else if ( is_string ( $key )) {
$moduleSettings [] = [
'name' => $key ,
'type' => 'string' ,
'description' => $value
];
2020-10-22 13:03:53 +02:00
} else {
$moduleSettings [] = array ( 'name' => $value , 'type' => 'string' );
}
2018-07-19 11:48:22 +02:00
}
}
2020-10-22 13:03:53 +02:00
$result [ $module [ 'name' ]] = $moduleSettings ;
2018-07-19 11:48:22 +02:00
}
}
}
return $result ;
}
2022-05-04 01:23:13 +02:00
public function executeActions ( $type , $user , $input , $logData , & $error = null )
{
$modules = $this -> getEnabledModules ( $user , null , $moduleFamily = 'Action' );
$sorted_modules = [];
2022-05-11 12:35:52 +02:00
if ( empty ( $modules ) || ! is_array ( $modules )) {
return true ;
}
2022-05-04 01:23:13 +02:00
foreach ( $modules [ 'modules' ] as $k => & $module ) {
if ( ! in_array ( $type , $module [ 'mispattributes' ][ 'hooks' ])) {
//unset($modules['modules'][$k]);
continue ;
}
$settingPath = 'Plugin.' . $module [ 'name' ] . '_' ;
$module [ 'weight' ] = Configure :: check ( $settingPath . 'weight' ) ? Configure :: read ( $settingPath . 'weight' ) : 0 ;
$module [ 'filters' ] = Configure :: check ( $settingPath . 'filters' ) ? json_decode ( Configure :: read ( $settingPath . 'filters' ), true ) : [];
foreach ( $module [ 'meta' ][ 'config' ] as $settingName => $settingData ) {
$module [ 'config' ][ $settingName ] = Configure :: check ( $settingPath . $settingName ) ? Configure :: read ( $settingPath . $settingName ) : $settingData [ 'value' ];
}
$sorted_modules [ $module [ 'weight' ]][] = $module ;
}
krsort ( $sorted_modules );
foreach ( $sorted_modules as $weight => $modules ) {
foreach ( $modules as $module ) {
$data = [
'module' => $module [ 'name' ],
'config' => empty ( $module [ 'config' ]) ? [] : $module [ 'config' ],
'data' => $input
];
2022-05-11 12:35:52 +02:00
if ( empty ( $module [ 'mispattributes' ][ 'blocking' ])) {
$this -> enqueueAction ( $data , $user );
return true ;
} else {
$result = $this -> executeAction ( $data );
if ( empty ( $result [ 'data' ]) || ! empty ( $result [ 'error' ])) {
$error = empty ( $result [ 'error' ]) ? __ ( 'Execution failed for module %s.' , $module [ 'name' ]) : $result [ 'error' ];
return false ;
}
2022-05-04 01:23:13 +02:00
}
}
}
return true ;
}
2022-05-11 12:35:52 +02:00
public function enqueueAction ( $data , $user )
{
/** @var Job $job */
$job = ClassRegistry :: init ( 'Job' );
$jobId = $job -> createJob ( $user , Job :: WORKER_PRIO , 'execute_action_module' , 'Module: ' . $data [ " module " ], 'Executing...' );
$args = [
'execute_action_module' ,
$user [ 'id' ],
$data ,
$jobId
];
$this -> getBackgroundJobsTool () -> enqueue (
BackgroundJobsTool :: PRIO_QUEUE ,
BackgroundJobsTool :: CMD_MODULE ,
$args ,
true ,
$jobId
);
return true ;
}
public function executeAction ( $data )
{
$result = $this -> queryModuleServer ( $data , false , 'Action' );
if ( ! empty ( $result [ 'error' ])) {
$this -> loadLog () -> createLogEntry (
'SYSTEM' ,
'warning' ,
empty ( $logData [ 'model' ]) ? 'Module' : $logData [ 'model' ],
empty ( $logData [ 'id' ]) ? 0 : $logData [ 'id' ],
sprintf (
'Executing %s action module on failed.' ,
$type
),
sprintf (
'Returned error: %s' ,
$result [ 'error' ]
)
);
}
return $result ;
}
2016-06-06 10:09:55 +02:00
}