From 21a14c4d4237cbe99fb88fcfc514f5b3d2ac03ba Mon Sep 17 00:00:00 2001 From: marcos Date: Mon, 17 Feb 2020 12:55:03 +0100 Subject: [PATCH] alert correlation update --- .../class/AlertCorrelationManager.class.php | 3559 +++++++++++++++++ .../include/javascript/correlated_alerts.js | 1285 ++++++ 2 files changed, 4844 insertions(+) create mode 100644 pandora_console/enterprise/include/class/AlertCorrelationManager.class.php create mode 100644 pandora_console/enterprise/include/javascript/correlated_alerts.js diff --git a/pandora_console/enterprise/include/class/AlertCorrelationManager.class.php b/pandora_console/enterprise/include/class/AlertCorrelationManager.class.php new file mode 100644 index 0000000000..3fa9efaebe --- /dev/null +++ b/pandora_console/enterprise/include/class/AlertCorrelationManager.class.php @@ -0,0 +1,3559 @@ +setBreadcrum([]); + + $this->help_url = [ + 1 => 'alert_configure', + 2 => 'alert_configure', + 3 => 'alert_rules', + 4 => 'alert_fields', + 5 => 'alert_triggering', + ]; + + $this->page = (int) get_parameter('page', 0); + + $this->id = (int) get_parameter('id', 0); + + $this->access = 'LM'; + $this->ajaxController = $ajaxPage; + $this->url = ui_get_full_url( + 'index.php?sec=galertas&sec2=enterprise/godmode/alerts/alert_correlation' + ); + + // Groups user access. + $this->groups = array_keys( + users_get_groups( + $config['id_user'], + 'LM', + true + ) + ); + + return $this; + } + + + /** + * Allowed methods to be called using AJAX request. + * + * @var array + */ + public $AJAXMethods = [ + 'addAlertActionForm', + 'addAlertAction', + 'deleteActionAlert', + 'addRowActionAjax', + 'standByAlert', + 'disabledAlert', + 'orderAlert', + 'createActionTableAjax', + ]; + + + /** + * Checks if target method is available to be called using AJAX. + * + * @param string $method Target method. + * + * @return boolean True allowed, false not. + */ + public function ajaxMethod(string $method):bool + { + return in_array($method, $this->AJAXMethods); + } + + + /** + * Show view Alert Correlation. + * + * @return void + */ + public function run() + { + global $config; + + // Include styles. + ui_require_css_file('wizard'); + ui_require_css_file('discovery'); + ui_require_css_file('alert'); + + if (empty($this->page) === true) { + $this->viewAlertList(); + } else { + $this->wizardAlert(); + } + + // Includes js files and document ready. + echo $this->loadJS(); + + } + + + /** + * Wizard alert. + * + * @return void + */ + public function wizardAlert() + { + // Prepare header and breadcrums. + $i = 0; + $bc = []; + $extra = ''; + + if ($this->id !== null) { + $extra = '&id='.$this->id; + } + + foreach ($this->labels as $key => $label) { + $bc[] = [ + 'link' => $this->url.(($i > 0) ? $extra.'&page='.$i : ''), + 'label' => $label, + 'selected' => ($this->page == $key), + ]; + + $i++; + } + + $this->prepareBreadcrum($bc); + + // Header. + ui_print_page_header( + $this->labels[$this->page], + '', + false, + $this->help_url[$this->page], + true, + '', + false, + '', + GENERIC_SIZE_TEXT, + '', + $this->printHeader(true) + ); + + if ($this->parse() === false) { + // Header. + ui_print_error_message(__($this->error)); + $this->printForm( + [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url.'&page='.($this->page - 1).'&id='.$this->id, + ], + 'inputs' => [ + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Go back'), + 'type' => 'submit', + 'attributes' => 'class="sub cancel"', + 'return' => true, + ], + ], + ], + ] + ); + exit(); + } + + switch ($this->page) { + case 1: + echo $this->wizardAlertStep1(); + break; + + case 2: + echo $this->wizardAlertStep2(); + break; + + case 3: + echo $this->wizardAlertStep3(); + break; + + case 4: + echo $this->wizardAlertStep4(); + break; + + case 5: + echo $this->wizardAlertStep5(); + break; + + default: + // Redirect users. + $this->page = 1; + echo $this->wizardAlertStep1(); + break; + } + + $this->printForm( + [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url.'&page='.($this->page - 1).'&id='.$this->id, + ], + 'inputs' => [ + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Go back'), + 'type' => 'submit', + 'attributes' => 'class="sub cancel"', + 'return' => true, + ], + ], + ], + ] + ); + + } + + + /** + * Initialize agent correlation. + * + * @param string $values Values for instantiate object. + * + * @return void + */ + public function getAlertCorrelationObject($values) + { + try { + $this->aC = new AlertCorrelation($values); + } catch (Exception $e) { + $this->aC = null; + $this->error = $e->getMessage(); + } + } + + + /** + * Parse wizard form. + * + * @return boolean + */ + public function parse() + { + global $config; + + if ($this->id !== 0) { + // Retrieve RCMD object. + $this->getAlertCorrelationObject($this->id); + $this->aC->get(); + } + + if ($this->page === 1) { + // Starting... + return true; + } + + if ($this->page === 2) { + // Parse response from wizard, page 1. + $name = get_parameter('name', ''); + $id_group = (int) get_parameter('id_group', 0); + $description = get_parameter('description', ''); + $priority = get_parameter('priority', 1); + + if ($name === '' || $id_group === null) { + if ((bool) $this->aC === false) { + // Accessing directly to item definition. + $this->error = __('Please follow the wizard.'); + return false; + } + + return true; + } else { + if (!check_acl( + $config['id_user'], + $this->access, + ($this->id === 0) ? $id_group : $this->aC->getIdGroup() + ) + ) { + $this->error = __( + 'You have no acess to edit this command.' + ); + return false; + } + + // Process update. + $values = [ + 'name' => $name, + 'description' => $description, + 'id_group' => $id_group, + 'priority' => $priority, + ]; + + if ((bool) $this->aC === false) { + // Not defined yet. Create. + $this->getAlertCorrelationObject($values); + $result = $this->aC->set(); + } else { + // Update. + $result = $this->aC->put($values); + } + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + $this->id = $this->aC->getId(); + + // Redirect to avoid double send. + $url = $this->url.'&page='.$this->page.'&id='.$this->id; + header( + 'Location: '.$url + ); + + // Redirected. Success. + exit; + } + } + } + + if ($this->page === 3) { + if ((bool) $this->aC === false) { + // Alert is not defined. + $this->error = __('Alert not found.'); + return false; + } + + $values = [ + 'monday' => get_parameter('days_week_mon', 0), + 'tuesday' => get_parameter('days_week_tue', 0), + 'wednesday' => get_parameter('days_week_wed', 0), + 'thursday' => get_parameter('days_week_thu', 0), + 'friday' => get_parameter('days_week_fri', 0), + 'saturday' => get_parameter('days_week_sat', 0), + 'sunday' => get_parameter('days_week_sun', 0), + 'special_days' => get_parameter_switch('special_days', 0), + 'time_from' => get_parameter('time_from', ''), + 'time_to' => get_parameter('time_to', ''), + 'max_alerts' => get_parameter('max_alerts', 0), + 'min_alerts' => get_parameter('min_alerts', 0), + 'time_threshold' => get_parameter('threshold', 86400), + 'mode' => get_parameter('evaluation', 'PASS'), + 'group_by' => get_parameter('grouped', ''), + ]; + + if ($values['monday'] === 0 + && $values['tuesday'] === 0 + && $values['wednesday'] === 0 + && $values['thursday'] === 0 + && $values['friday'] === 0 + && $values['saturday'] === 0 + && $values['sunday'] === 0 + && $values['special_days'] === 0 + && $values['time_from'] === '' + && $values['time_to'] === '' + && $values['max_alerts'] === 0 + && $values['min_alerts'] === 0 + && $values['time_threshold'] === 86400 + && $values['mode'] === 'PASS' + && $values['group_by'] === '' + ) { + // Default values. Check if user can edit this alert. + return true; + } else { + // Update. + $result = $this->aC->put($values); + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + return true; + } + } + } + + if ($this->page === 4) { + if ((bool) $this->aC === false) { + // Alert is not defined. + $this->error = __('Alert not found.'); + return false; + } + + $rules = get_parameter('rule-stack', false); + + if ((bool) $rules !== false) { + $rules = json_decode( + base64_decode($rules), + true + ); + + if (json_last_error() === JSON_ERROR_NONE) { + $rules = array_reduce( + $rules, + function ($carry, $item) { + $carry[$item['order']][] = io_safe_output($item); + return $carry; + } + ); + + if ($rules === null) { + $rules = []; + } + + $this->aC->addRules($rules); + + return true; + } else { + $this->error = __('JSON decoding error. Please call support.'); + $this->error .= json_last_error_msg(); + return false; + } + } else { + // No changes. + return true; + } + } + + if ($this->page === 5) { + if ((bool) $this->aC === false) { + // Alert is not defined. + $this->error = __('Alert not found.'); + return false; + } + + $this->id_action = (int) \get_parameter('id_action', 0); + $action = (int) \get_parameter('actions_alert'); + $fires_min = (int) \get_parameter('fires_min', 0); + $fires_max = (int) \get_parameter('fires_max', 0); + $threshold = (int) \get_parameter('threshold'); + + // Delete Action. + $delete_action = (int) \get_parameter('delete_action', 0); + if ($delete_action === 1) { + if ($this->id_action !== 0) { + $result = $this->aC->deleteActionAlert($this->id_action); + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + // Restore value. + $this->id_action = 0; + return true; + } + } + + return false; + } + + // Create or update actions alerts. + $add_action = \get_parameter('create-action', ''); + if (empty($add_action) === false) { + if (isset($action) === false + || empty($action) === true + ) { + return false; + } + + $values = []; + $values['fires_min'] = $fires_min; + $values['fires_max'] = $fires_max; + $values['module_action_threshold'] = $threshold; + + $result = $this->aC->setActionAlert($action, $values); + $values['id_alert_action'] = $action; + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + return true; + } + + return true; + } + + $update_action = \get_parameter('update-action', ''); + if (empty($update_action) === false) { + if (isset($action) === false + || empty($action) === true + || isset($this->id_action) === false + || empty($this->id_action) === true + ) { + return false; + } + + $values = []; + $values['fires_min'] = $fires_min; + $values['fires_max'] = $fires_max; + $values['module_action_threshold'] = $threshold; + $values['id_alert_action'] = $action; + + $result = $this->aC->putActionAlert($this->id_action, $values); + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + // Restore value. + $this->id_action = 0; + return true; + } + + return true; + } + + $values = []; + for ($i = 1; $i <= 10; $i++) { + $field = get_parameter('field'.$i, ''); + + if ($field !== '') { + $values['field'.$i] = $field; + } + } + + if (count($values) > 0) { + // Update. + $result = $this->aC->put($values); + + if (isset($result) === true + && is_array($result) === true + && $result['error'] === true + ) { + $this->error = $result['msg_error']; + return false; + } else { + return true; + } + } + + return true; + } + + $this->error = __('Page not found'); + return false; + } + + + /** + * Wizard configuration. + * + * @return string + */ + public function wizardAlertStep1():string + { + // Initialize vars. + $name = ''; + $group = 0; + $description = ''; + $priority = 1; + if ($this->id !== 0) { + // Retrieve RCMD object. + $name = $this->aC->getName(); + $group = $this->aC->getIdGroup(); + $description = $this->aC->getDescription(); + $priority = $this->aC->getPriority(); + } + + $form = [ + 'action' => $this->url.'&page=2&id='.$this->id, + 'method' => 'POST', + 'id' => 'general_filters_alert', + ]; + + $inputs = [ + [ + 'block_id' => 'name-group', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Name'), + 'arguments' => [ + 'type' => 'text', + 'id' => 'name', + 'name' => 'name', + 'value' => $name, + 'return' => true, + 'required' => true, + ], + + ], + [ + 'label' => __('Group'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'id_group', + 'name' => 'id_group', + 'fields' => users_get_groups_for_select( + $config['id_user'], + 'AR', + true, + true, + false + ), + 'selected' => $group, + ], + ], + ], + + ], + [ + 'block_id' => 'description', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Description'), + 'arguments' => [ + 'name' => 'description', + 'type' => 'textarea', + 'value' => $description, + 'return' => true, + 'rows' => 1, + 'columns' => 1, + 'size' => 25, + ], + ], + ], + + ], + [ + 'block_id' => 'priority', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Priority'), + 'class' => 'flex-item', + 'arguments' => [ + 'type' => 'select', + 'id' => 'priority', + 'name' => 'priority', + 'fields' => \get_priorities(), + 'selected' => $priority, + ], + ], + ], + + ], + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Next'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true, + true + ); + + return $output; + } + + + /** + * Wizard condition. + * + * @return string + */ + public function wizardAlertStep2():string + { + $id_template = 0; + + // Initialize vars. + $monday = 1; + $tuesday = 1; + $wednesday = 1; + $thursday = 1; + $friday = 1; + $saturday = 1; + $sunday = 1; + $special_days = 0; + $time_from = ''; + $time_to = ''; + $max_alerts = 0; + $min_alerts = 0; + $time_threshold = 86400; + $mode = 'PASS'; + $group_by = ''; + if ($this->id !== 0) { + // Retrieve RCMD object. + $monday = $this->aC->getMonday(); + $tuesday = $this->aC->getTuesday(); + $wednesday = $this->aC->getWednesday(); + $thursday = $this->aC->getThursday(); + $friday = $this->aC->getFriday(); + $saturday = $this->aC->getSaturday(); + $sunday = $this->aC->getSunday(); + $special_days = $this->aC->getSpecialDays(); + $time_from = $this->aC->getTimeFrom(); + $time_to = $this->aC->getTimeTo(); + $max_alerts = $this->aC->getMaxAlerts(); + $min_alerts = $this->aC->getMinAlerts(); + $time_threshold = $this->aC->getTimeThreshold(); + $mode = $this->aC->getMode(); + $group_by = $this->aC->getGroupBy(); + } + + // Arrays for select. + $templates = array_reduce( + \alerts_get_alert_templates(false, ['id', 'name']), + function ($carry, $item) { + $carry[$item['id']] = $item['name']; + return $carry; + }, + [] + ); + $templates[0] = __('None'); + + $evaluations = [ + 'PASS' => __('Pass'), + 'DROP' => __('Drop'), + ]; + + $groupeds = [ + '' => __('None'), + 'id_agente' => __('Agent'), + 'id_agentmodule' => __('Module'), + 'id_alert_am' => __('Module alert'), + 'id_grupo' => __('Group'), + ]; + + // FORM. + $form = [ + 'action' => $this->url.'&page=3&id='.$this->id, + 'method' => 'POST', + 'id' => 'conditions_filters_alert', + 'extra' => 'novalidate', + + ]; + + // TODO: Load from template. + $inputs = [ + // [ + // 'block_id' => 'load-template', + // 'class' => 'flex-row flex-start w100p', + // 'direct' => 1, + // 'block_content' => [ + // [ + // 'label' => __('Load from template'), + // 'arguments' => [ + // 'type' => 'select', + // 'id' => 'template', + // 'name' => 'template', + // 'fields' => $templates, + // 'selected' => $id_template, + // ], + // ], + // ], + // ], + [ + 'block_id' => 'days-week', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Days a week'), + 'arguments' => [ + 'type' => 'multicheck', + 'id' => 'days_week', + 'name' => 'days_week', + 'data' => [ + 'mon' => __('Mon'), + 'tue' => __('Tue'), + 'wed' => __('Wed'), + 'thu' => __('Thu'), + 'fri' => __('Fri'), + 'sat' => __('Sat'), + 'sun' => __('Sun'), + ], + 'checked' => [ + 'mon' => $monday, + 'tue' => $tuesday, + 'wed' => $wednesday, + 'thu' => $thursday, + 'fri' => $friday, + 'sat' => $saturday, + 'sun' => $sunday, + ], + ], + ], + ], + ], + [ + 'block_id' => 'special-days-list', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Use special days list'), + 'arguments' => [ + 'name' => 'special_days', + 'id' => 'special-days', + 'type' => 'switch', + 'value' => $special_days, + ], + ], + ], + ], + [ + 'block_id' => 'time-from-to', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Time'), + ], + [ + 'label' => __('from'), + 'arguments' => [ + 'name' => 'time_from', + 'id' => 'time_from', + 'type' => 'text', + 'value' => $time_from, + 'size' => 20, + ], + ], + [ + 'label' => __('to'), + 'arguments' => [ + 'name' => 'time_to', + 'id' => 'time_to', + 'type' => 'text', + 'value' => $time_to, + 'size' => 20, + ], + ], + ], + ], + [ + 'block_id' => 'from-to-threshold', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Execute alert'), + ], + [ + 'label' => __('from'), + 'arguments' => [ + 'name' => 'min_alerts', + 'id' => 'min_alerts', + 'type' => 'number', + 'value' => $min_alerts, + 'size' => 5, + ], + ], + [ + 'label' => __('to'), + 'arguments' => [ + 'name' => 'max_alerts', + 'id' => 'max_alerts', + 'type' => 'number', + 'value' => $max_alerts, + 'size' => 5, + ], + ], + [ + 'label' => __('times in'), + 'arguments' => [ + 'name' => 'threshold', + 'type' => 'interval', + 'value' => $time_threshold, + 'nothing' => __('None'), + 'nothing_value' => 0, + ], + ], + [ + 'label' => __('threshold').'.', + ], + ], + ], + [ + 'block_id' => 'evaluation', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Rule evaluation mode'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'evaluation', + 'name' => 'evaluation', + 'fields' => $evaluations, + 'selected' => $mode, + ], + ], + ], + ], + [ + 'block_id' => 'grouped', + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Grouped by'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'grouped', + 'name' => 'grouped', + 'fields' => $groupeds, + 'selected' => $group_by, + ], + ], + ], + ], + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Next'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true, + true + ); + + return $output; + } + + + /** + * Wizard Rules. + * + * @return string + */ + public function wizardAlertStep3():string + { + global $config; + + $output = '
'; + $output .= '
'; + $output .= '
    '; + $output .= '
  • '.__('Available items').'
  • '; + $output .= '
  • '; + $output .= '
    '; + + $nexos = [ + [ + 'title' => '(', + 'id' => 'block-start', + ], + [ + 'title' => ')', + 'id' => 'block-end', + ], + ]; + + foreach ($nexos as $key => $value) { + // Attributes div. + $attributes = 'draggable="true"'; + $attributes .= 'id="'.$value['id'].'"'; + $attributes .= 'ondragstart="drag(event)"'; + if ($value['id'] == 'block-end') { + $attributes .= 'class="blocks block field opacityElements"'; + } else { + $attributes .= 'class="blocks block field"'; + } + + $output .= '
    '; + $output .= $value['title']; + $output .= '
    '; + } + + $output .= '
    '; + + $output .= '
  • '; + + $output .= '
  • '; + $output .= ''; + $output .= '
    '; + + $fields = []; + + if (is_metaconsole() !== true) { + // Elasticsearch is not configured yet in Metaconsole. + // We can initialize backend using multiples nodes, but + // we are not fully sure how system will behave. + $fields = [ + [ + 'title' => __('Log content'), + 'type' => 'log', + 'id' => 'fields-log-content', + ], + [ + 'title' => __('Log source'), + 'type' => 'log', + 'id' => 'fields-log-source', + ], + [ + 'title' => __('Log agent'), + 'type' => 'log', + 'id' => 'fields-log-agent', + ], + ]; + } + + // Groups for variable selections. Keep 'grp' for reverse resolution. + $grp = users_get_groups_for_select( + $config['id_user'], + 'AR', + true, + true, + false + ); + + $groups = []; + foreach ($grp as $k => $v) { + $groups[] = [ + 'id' => $k, + 'title' => io_safe_output($v), + ]; + } + + // Severities available for variable selection. + $svr = get_priorities(); + $severity = []; + foreach ($svr as $k => $v) { + $severity[] = [ + 'id' => $k, + 'title' => io_safe_output($v), + ]; + } + + // Event types. + $evt_types = AlertCorrelation::getEventTypes(); + $event_types = []; + foreach ($evt_types as $k => $v) { + $event_types[] = [ + 'id' => $k, + 'title' => __($v), + ]; + } + + // Tags names. + $select_tags = tags_search_tag(false, false, true); + $tags_types = []; + foreach ($select_tags as $k => $v) { + $tags_types[] = [ + 'id' => $k, + 'title' => __($v), + ]; + } + + $fields = array_merge( + $fields, + [ + [ + 'title' => __('Event content'), + 'type' => 'event', + 'id' => 'fields-event-content', + ], + [ + 'title' => __('Event user comment'), + 'type' => 'event', + 'id' => 'fields-event-user-comment', + ], + [ + 'title' => __('Event agent'), + 'type' => 'event', + 'id' => 'fields-event-agent', + ], + [ + 'title' => __('Event module'), + 'type' => 'event', + 'id' => 'fields-event-module', + ], + [ + 'title' => __('Event module alerts'), + 'type' => 'event', + 'id' => 'fields-module-alerts', + ], + [ + 'title' => __('Event group'), + 'type' => 'event', + 'id' => 'fields-event-group', + ], + [ + 'title' => __('Event group Recursive'), + 'type' => 'event', + 'id' => 'fields-event-group-recursive', + ], + [ + 'title' => __('Event severity'), + 'type' => 'event', + 'id' => 'fields-event-severity', + ], + [ + 'title' => __('Event tag'), + 'type' => 'event', + 'id' => 'fields-event-tag', + ], + [ + 'title' => __('Event user'), + 'type' => 'event', + 'id' => 'fields-event-user', + ], + [ + 'title' => __('Event type'), + 'type' => 'event', + 'id' => 'fields-event-type', + ], + ] + ); + + foreach ($fields as $key => $value) { + // Attributes div. + $attributes = 'draggable="true"'; + $attributes .= 'id="'.$value['id'].'"'; + $attributes .= 'ondragstart="drag(event)"'; + $attributes .= 'class="fields field '.$value['type'].' opacityElements"'; + + $output .= '
    '; + $output .= $value['title']; + $output .= '
    '; + } + + $output .= '
    '; + $output .= '
  • '; + + $output .= '
  • '; + $output .= ''; + + $operators = [ + [ + 'title' => '>', + 'id' => 'operators-greater-than', + ], + [ + 'title' => '<', + 'id' => 'operators-smaller than', + ], + [ + 'title' => '>=', + 'id' => 'operators-greater-than-equal', + ], + [ + 'title' => '<=', + 'id' => 'operators-greater-smaller-equal', + ], + [ + 'title' => '==', + 'id' => 'operators-equal', + ], + [ + 'title' => '!=', + 'id' => 'operators-different', + ], + [ + 'title' => 'REGEX', + 'id' => 'operators-contains', + ], + [ + 'title' => 'NOT REGEX', + 'id' => 'operators-not-contains', + ], + ]; + + $output .= '
    '; + + foreach ($operators as $key => $value) { + // Attributes div. + $attributes = 'draggable="false"'; + $attributes .= 'id="'.$value['id'].'"'; + $attributes .= 'ondragstart="drag(event)"'; + $attributes .= 'class="operators field opacityElements"'; + + $output .= '
    '; + $output .= $value['title']; + $output .= '
    '; + } + + $output .= '
    '; + $output .= '
  • '; + + $output .= '
  • '; + $output .= ''; + $output .= '
    '; + + // Attributes div. + $attributes = 'id="variable-text"'; + + $attributes .= 'draggable="false"'; + $attributes .= 'ondragstart="drag(event)"'; + $attributes .= 'class="variables variable field opacityElements"'; + + $output .= '
    '; + $output .= __('Double click to assign value'); + $output .= '
    '; + $output .= '
    '; + $output .= '
  • '; + + $output .= '
  • '; + $output .= ''; + + $modifiers = [ + [ + 'title' => __('Time window'), + 'id' => 'modifier-time-window', + ], + [ + 'title' => __('Count'), + 'id' => 'modifier-count', + ], + ]; + + $output .= '
    '; + foreach ($modifiers as $key => $value) { + // Attributes div. + $attributes = 'draggable="false"'; + $attributes .= 'id="'.$value['id'].'"'; + $attributes .= 'ondragstart="drag(event)"'; + $attributes .= 'class="modifiers modifier field opacityElements"'; + + $output .= '
    '; + $output .= $value['title']; + $output .= '
    '; + } + + $output .= '
    '; + $output .= '
  • '; + + $output .= '
  • '; + $output .= '
    '; + + $nexos = [ + [ + 'title' => 'AND', + 'id' => 'nexo-and', + ], + [ + 'title' => 'NAND', + 'id' => 'nexo-nand', + ], + [ + 'title' => 'OR', + 'id' => 'nexo-or', + ], + [ + 'title' => 'NOR', + 'id' => 'nexo-nor', + ], + [ + 'title' => 'XOR', + 'id' => 'nexo-xor', + ], + [ + 'title' => 'NXOR', + 'id' => 'nexo-nxor', + ], + ]; + + foreach ($nexos as $key => $value) { + // Attributes div. + $attributes = 'draggable="false"'; + $attributes .= 'id="'.$value['id'].'"'; + $attributes .= 'ondragstart="drag(event)"'; + $attributes .= 'class="nexos nexo field opacityElements"'; + + $output .= '
    '; + $output .= $value['title']; + $output .= '
    '; + } + + $output .= '
    '; + + $output .= '
  • '; + $output .= '
'; + + $stack = $this->aC->getRuleStack(); + + $output .= '
'; + $output .= ''.__('Rule definition').''; + $output .= '
'; + + $i = 0; + $current_block_order = 0; + if (is_array($stack) === true) { + foreach ($stack as $item) { + // First nexo on a rule is global nexus. + if ($item['order'] > 0 + && $item['type'] == 'nexos' + && ($i++) === 0 + ) { + // We start block with NEXOS after first rule. + $output .= '
aC->extractClassItem($item).' rule_'.$item['order']; + // Attributes div. + $attributes = 'draggable="false"'; + + $text = io_safe_output($item['value']); + if ($item['type'] == 'fields') { + $text = $this->aC->getFieldText($item['value']); + } + + /* + * Update attributes. + */ + + $attributes .= ' id="'.$item['var_id'].'"'; + $add_action = 1; + if ($item['type'] == 'variables') { + /* + * VARIABLES. + */ + + $attributes .= ' var_id="'.$item['var_id'].'"'; + $text = str_replace(' ', ' ', $text); + $text = str_replace("\n", '
', $text); + + // Set ID to ensure edition. + if ($latest['type'] == 'modifiers') { + // Variable FOR modifier. + $attributes .= ' id="'.strtolower($latest['value']); + $attributes .= '-'.$item['order'].'"'; + } else { + // Variable FOR field. + $attributes .= ' id="'.$prev['value']; + $attributes .= '-'.$item['order'].'"'; + + if ($prev['value'] === 'fields-event-group' + || $prev['value'] === 'fields-event-group-recursive' + ) { + // Variable FOR group. + $text = io_safe_output($grp[$text]); + } else if ($prev['value'] === 'fields-event-severity') { + // Variable FOR severity. + $text = io_safe_output($svr[$text]); + if ($text === '') { + $text = __('Any'); + } + } else if ($prev['value'] === 'fields-event-type') { + $text = __($evt_types[$text]); + } else if ($prev['value'] === 'fields-event-tag') { + $text = __($select_tags[$text]); + } + } + } else if ($item['type'] == 'nexos' && $i > 0) { + // Only 'global' nexo could be updated. + // Blocks internal ones are always 'AND'. + $add_action = 0; + } else { + // Avoid text select. + $class .= ' noselect'; + } + + $attributes .= ' class="'.$class.'" order='.$item['order'].' '; + + // Fire edit 'mode'. + if ($add_action === 1) { + $attributes .= ' ondblclick="editMe(this,\''.$item['type'].'\');"'; + } + + if ($item['type'] == 'nexos') { + $output .= '
'; + } + + $output .= '
'; + $output .= $text; + $output .= '
'; + + if ($item['id'] == 'block-end') { + // Close div_parent (rule order). + $output .= '
'; + $current_block_order = $item['order']; + $i = 0; + } + + $prev = $latest; + $latest = $item; + } + } else { + $stack = []; + } + + // Rules. + $output .= '
'; + + // Rule with title. + $output .= '
'; + + // Global. + $output .= '
'; + + $output .= ''; + + $form = [ + 'action' => $this->url.'&page=4&id='.$this->id, + 'method' => 'POST', + 'id' => 'rule-builder', + ]; + + $output .= '
'; + + $agents = agents_get_agents(); + $agents_select = []; + foreach ($agents as $agent => $value) { + $agents_select[$agent] = array_merge( + $agents_select, + [ + 'id' => $value['id_agente'], + 'title' => io_safe_output($value['nombre']), + ] + ); + } + + $modules = db_get_all_rows_sql('select * from tmodule'); + $modules_select = []; + foreach ($modules as $module => $value) { + $modules_select[$module] = array_merge( + $modules_select, + [ + 'id' => $value['id_module'], + 'title' => io_safe_output($value['name']), + ] + ); + } + + $inputs = [ + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'name' => 'rule-stack', + 'id' => 'rule-stack', + 'value' => base64_encode(json_encode($stack)), + 'quotes' => true, + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'fields-select-content', + 'value' => base64_encode(json_encode($fields)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'groups-select-content', + 'value' => base64_encode(json_encode($groups)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'severity-select-content', + 'value' => base64_encode(json_encode($severity)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'event-types-select-content', + 'value' => base64_encode(json_encode($event_types)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'tags-types-select-content', + 'value' => base64_encode(json_encode($tags_types)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'agents-select-content', + 'value' => base64_encode(json_encode($agents_select)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'modules-select-content', + 'value' => base64_encode(json_encode($modules_select)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'modules-alerts-select-content', + 'value' => base64_encode(json_encode($event_modules_alerts)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'event_user-select-content', + 'value' => base64_encode(json_encode($event_user)), + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'block-status', + 'value' => '0', + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden_extended', + 'id' => 'block-order', + 'value' => $current_block_order, + ], + ], + [ + 'class' => 'action-buttons rule-builder-actions', + 'direct' => false, + 'wrapper' => 'div', + 'block_content' => [ + [ + 'class' => 'margin-right-2', + 'arguments' => [ + 'name' => 'removelast', + 'label' => __('Remove rule'), + 'type' => 'button', + 'attributes' => 'class="sub delete"', + 'return' => true, + 'script' => 'removeLastRule()', + ], + ], + [ + 'class' => 'margin-right-2', + 'arguments' => [ + 'name' => 'removelastitem', + 'label' => __('Remove item'), + 'type' => 'button', + 'attributes' => 'class="sub delete"', + 'return' => true, + 'script' => 'removeLast(event)', + ], + ], + [ + 'class' => 'margin-right-2', + 'arguments' => [ + 'name' => 'cleanup', + 'label' => __('Cleanup'), + 'type' => 'button', + 'attributes' => 'class="sub delete"', + 'return' => true, + 'script' => 'paneCleanup()', + ], + ], + [ + 'arguments' => [ + 'name' => 'undo', + 'label' => __('Reset'), + 'type' => 'button', + 'attributes' => 'class="sub upd"', + 'return' => true, + 'script' => 'location.reload();', + ], + ], + ], + ], + [ + 'arguments' => [ + 'name' => 'rule', + 'label' => __('Next'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + ], + ], + ]; + + $output .= $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + + return $output; + } + + + /** + * Wizard Actions. + * + * @return string + */ + public function wizardAlertStep4():string + { + $fields = []; + + $form = [ + 'action' => $this->url.'&page=5&id='.$this->id, + 'method' => 'POST', + 'id' => 'advanced_filters_alert', + ]; + + for ($i = 1; $i <= 10; $i++) { + if ($this->id !== 0) { + $fields[$i] = $this->aC->{'getField'.$i}(); + } + + $inputs[] = [ + 'block_id' => 'field-'.$i, + 'class' => 'flex-row-vcenter flex-space-around w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Field %s', $i).ui_print_help_icon('alert_macros', true), + 'arguments' => [ + 'name' => 'field'.$i, + 'type' => 'textarea', + 'value' => (isset($fields[$i]) === true) ? $fields[$i] : '', + 'return' => true, + 'rows' => 1, + 'columns' => 1, + 'size' => 25, + ], + ], + ], + ]; + } + + $inputs[] = [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Next'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true, + true + ); + + return $output; + } + + + /** + * Wizard triggering. + * + * @return string + */ + public function wizardAlertStep5():string + { + $fields = []; + if ($this->id < 0) { + exit(); + } + + $mode = $this->aC->getMode(); + $group_by = $this->aC->getGroupBy(); + + // Info Alert. + $info_alert = '
'; + $info_alert .= '
'; + $info_alert .= $this->getTableDaysAlert(); + $info_alert .= '
'; + $info_alert .= '
'; + $info_alert .= $this->getTableTimeAlert(); + $info_alert .= '
'; + $info_alert .= '
'; + $info_alert .= '
'; + $info_alert .= $this->getTableConditionsAlert(); + $info_alert .= '
'; + + $output .= ui_print_toggle( + [ + 'name' => __('Triggering Condition'), + 'content' => $info_alert, + 'title' => __('Triggering Condition'), + 'hidden_default' => false, + ] + ); + + $output .= $this->formActionAlerts(); + + $output .= $this->listActionAlerts(); + + $output .= $this->showActionAlerts(); + + $attr = 'class="mode_table mode_table_firing action_details"'; + $output .= '
'; + + $form = [ + 'action' => $this->url.'&page=0', + 'method' => 'POST', + 'id' => 'actions_filters_alert', + ]; + + $inputs[] = [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Finish'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ]; + + $output .= $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + + return $output; + } + + + /** + * Print Info days Correlation alerts. + * + * @return string + */ + public function getTableDaysAlert():string + { + $monday = $this->aC->getMonday(); + $tuesday = $this->aC->getTuesday(); + $wednesday = $this->aC->getWednesday(); + $thursday = $this->aC->getThursday(); + $friday = $this->aC->getFriday(); + $saturday = $this->aC->getSaturday(); + $sunday = $this->aC->getSunday(); + + $table_days = new stdClass(); + $table_days->width = '100%'; + $table_days->class = 'info_table'; + $table_days->data = []; + $table_days->styleTable = 'text-align: center;'; + $table_days->head[0] = __('Mon'); + $table_days->head[1] = __('Tue'); + $table_days->head[2] = __('Wed'); + $table_days->head[3] = __('Thu'); + $table_days->head[4] = __('Fri'); + $table_days->head[5] = __('Sat'); + $table_days->head[6] = __('Sun'); + + $table_days->data[0] = array_fill( + 0, + 7, + html_print_image('images/blade.png', true) + ); + + $days = []; + if ($monday === 1) { + $table_days->data[0][0] = html_print_image('images/tick.png', true); + } + + if ($tuesday === 1) { + $table_days->data[0][1] = html_print_image('images/tick.png', true); + } + + if ($wednesday === 1) { + $table_days->data[0][2] = html_print_image('images/tick.png', true); + } + + if ($thursday === 1) { + $table_days->data[0][3] = html_print_image('images/tick.png', true); + } + + if ($friday === 1) { + $table_days->data[0][4] = html_print_image('images/tick.png', true); + } + + if ($saturday === 1) { + $table_days->data[0][5] = html_print_image('images/tick.png', true); + } + + if ($sunday === 1) { + $table_days->data[0][6] = html_print_image('images/tick.png', true); + } + + return \html_print_table($table_days, true); + } + + + /** + * Print Time Correlation alerts. + * + * @return string + */ + public function getTableTimeAlert():string + { + $time_from = $this->aC->getTimeFrom(); + $time_to = $this->aC->getTimeTo(); + + $table_time = new stdClass(); + $table_time->width = '100%'; + $table_time->class = 'info_table'; + $table_time->styleTable = 'text-align: center;'; + $table_time->data = []; + + if ($time_from === $time_to) { + $table_time->head[0] = '00:00:00 - 23:59:59'; + $table_time->data[0][0] = html_print_image( + 'images/tick.png', + true + ); + } else { + $from_array = explode(':', $time_from); + $hours = ($from_array[0] * SECONDS_1HOUR); + $minutes = ($from_array[1] * SECONDS_1MINUTE); + $from = ($hours + $minutes + $from_array[2]); + $to_array = explode(':', $time_to); + $hours_to = ($to_array[0] * SECONDS_1HOUR); + $minutes_to = ($to_array[1] * SECONDS_1MINUTE); + $to = ($hours_to + $minutes_to + $to_array[2]); + if ($to > $from) { + if ($time_from !== '00:00:00') { + $table_time->head[0] = '00:00:00 - '.$time_from; + $table_time->data[0][0] = html_print_image( + 'images/blade.png', + true + ); + } + + $table_time->head[1] = $time_from.' - '.$time_to; + $table_time->data[0][1] = html_print_image( + 'images/tick.png', + true + ); + + if ($time_to !== '23:59:59') { + $table_time->head[2] = $time_to.' - 23:59:59'; + $table_time->data[0][2] = html_print_image( + 'images/blade.png', + true + ); + } + } else { + if ($time_to !== '00:00:00') { + $table_time->head[0] = '00:00:00 - '.$time_to; + $table_time->data[0][0] = html_print_image( + 'images/tick.png', + true + ); + } + + $table_time->head[1] = $time_to.' - '.$time_from; + $table_time->data[0][1] = html_print_image( + 'images/blade.png', + true + ); + + if ($time_from !== '23:59:59') { + $table_time->head[2] = $time_from.' - 23:59:59'; + $table_time->data[0][2] = html_print_image( + 'images/tick.png', + true + ); + } + } + + $data[1] = $time_from.' / '.$time_to; + } + + return \html_print_table($table_time, true); + } + + + /** + * Table info conditions Alerts. + * + * @return string + */ + public function getTableConditionsAlert():string + { + $special_days = $this->aC->getSpecialDays(); + $max_alerts = $this->aC->getMaxAlerts(); + $min_alerts = $this->aC->getMinAlerts(); + $time_threshold = $this->aC->getTimeThreshold(); + + $table_conditions = new stdClass(); + $table_conditions->width = '95%'; + $table_conditions->class = 'no-class'; + $table_conditions->data = []; + $table_conditions->size = []; + $table_conditions->size[0] = '30%'; + $table_conditions->data[] = $data; + + $data[0] = ''.__('Use special days list').''; + $data[1] = (isset($special_days) && $special_days === 1) ? __('Yes') : __('No'); + $table_conditions->data[] = $data; + + $data[0] = ''.__('Time threshold').''; + $data[1] = human_time_description_raw($time_threshold, true); + $table_conditions->data[] = $data; + + $data[0] = ''; + $data[0] .= __('Number of alerts').' ('.__('Min').'/'.__('Max').')'; + $data[0] .= ''; + $data[1] = $min_alerts.'/'.$max_alerts; + $table_conditions->data[] = $data; + + return \html_print_table($table_conditions, true); + } + + + /** + * Send form create actions AJAX. + * + * @return string. + */ + public function formActionAlerts():string + { + $form = [ + 'action' => $this->url.'&page=5&id='.$this->id, + 'method' => 'POST', + 'id' => 'add_actions_alerts', + ]; + + $filter_groups = implode(',', $this->groups); + + $actions = $this->aC->getAlertsActions( + 'id_group IN ('.$filter_groups.')', + true + ); + + $inputs = $this->inputsActionAlerts($actions); + + $inputs[] = [ + 'arguments' => [ + 'name' => ($this->id_action === 0) ? 'create-action' : 'update-action', + 'label' => ($this->id_action === 0) ? __('Add') : __('Update'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ]; + + $inputs[] = [ + 'arguments' => [ + 'name' => 'id_action', + 'type' => 'hidden', + 'value' => $this->id_action, + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true, + true + ); + + return $output; + + } + + + /** + * Print table actions. + * + * @return string + */ + public function listActionAlerts():string + { + // Extract actions info for alert. + $actions = AlertCorrelation::getActionsAlert($this->id); + + // Initialize table. + $table = new stdClass(); + $table->width = '100%'; + $table->class = 'info_table'; + $table->id = 'table-actions'; + + // Size. + $table->size = []; + + // Head. + $table->head = []; + $table->head[0] = ''.__('Actions').''; + $table->head[1] = ''.__('Firing').''; + + $table->head[2] = ''.__('Treshold').''; + $table->head[3] = ''.__('Opions').''; + + // Data. + $table->data = []; + if (empty($actions) === false) { + foreach ($actions as $action) { + $url = $this->url.'&page=5&id='.$this->id; + $url .= '&id_action='.$action['id']; + // Name action with link. + $data[0] = ''; + $data[0] .= $action['name']; + $data[0] .= ''; + + // Check do not exceed limit defined in alert. + if ($action['fires_min'] < $this->aC->getMinAlerts()) { + $action['fires_min'] = $this->aC->getMinAlerts(); + } + + if ($action['fires_max'] > $this->aC->getMaxAlerts()) { + $action['fires_max'] = $this->aC->getMaxAlerts(); + } + + $data[1] = ''; + $error = false; + + $action['escalation'] = alerts_get_action_escalation($action); + + $acum = null; + $from = 1; + $final = count($action['escalation']); + foreach ($action['escalation'] as $k => $v) { + if (isset($acum) === false) { + $acum = $v; + } else if ($acum !== $v || $k === $final) { + if ($k === $final) { + $data[1] .= '( '.__('From').' '.$from.' '.__('to').' '.($k).' ) '; + } else if (($k - $from) === 1) { + $data[1] .= '( '.$from.' ) '; + } else { + $data[1] .= '( '.__('From').' '.$from.' '.__('to').' '.($k - 1).' ) '; + } + + if ($acum > 0) { + $data[1] .= html_print_image( + 'images/tick.png', + true + ); + } else { + $data[1] .= html_print_image( + 'images/blade.png', + true + ); + } + + $data[1] .= ' '; + $from = $k; + $acum = $v; + } + } + + if ($data[1] === '') { + $data[1] = __('Always'); + } + + // Treshold. + $data[2] = human_time_description_raw( + $action['module_action_threshold'], + true, + 'tiny' + ); + + // Actions. + $data[3] = ''; + // Edit Alert. + $data[3] .= ''; + $data[3] .= html_print_input_image( + 'edit', + 'images/config.png', + 1, + '', + true, + ['title' => __('Edit')] + ); + $data[3] .= ''; + + // Delete Alert. + $data[3] .= ''; + $data[3] .= html_print_input_image( + 'del', + 'images/cross.png', + 1, + '', + true, + ['title' => __('Delete')] + ); + $data[3] .= ''; + + array_push($table->data, $data); + } + + $return .= html_print_table($table, true); + } else { + $return = ui_print_info_message( + __('There are no defined actions for this alert'), + '', + true + ); + } + + return $return; + + } + + + /** + * Print inputs valid for triggering and modal global view. + * + * @param array $actions Actions select. + * + * @return array + */ + private function inputsActionAlerts(array $actions):array + { + $id_alert_action = 0; + $fires_min = null; + $fire_max = null; + $module_action_threshold = $this->aC->getTimeThreshold(); + if ($this->id_action !== 0) { + $action = AlertCorrelation::getActionAlert( + $this->id, + $this->id_action + ); + $id_alert_action = $action['id_alert_action']; + $fires_min = $action['fires_min']; + $fires_max = $action['fires_max']; + $module_action_threshold = $action['module_action_threshold']; + } + + return [ + [ + 'class' => 'flex-row-vcenter flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Actions'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'actions_alert', + 'name' => 'actions_alert', + 'fields' => $actions, + 'nothing' => __('None'), + 'nothing_value' => 0, + 'selected' => $id_alert_action, + ], + ], + ], + ], + [ + 'block_id' => 'time-from-to', + 'class' => 'flex-row-vcenter flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Number of alerts match'), + ], + [ + 'arguments' => [ + 'name' => 'fires_min', + 'id' => 'fires_min', + 'type' => 'number', + 'size' => 5, + 'value' => $fires_min, + ], + ], + [ + 'label' => __('to'), + 'arguments' => [ + 'name' => 'fires_max', + 'id' => 'fires_max', + 'type' => 'number', + 'size' => 5, + 'value' => $fires_max, + ], + ], + ], + ], + [ + 'class' => 'flex-row-vcenter flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Treshold'), + 'arguments' => [ + 'name' => 'threshold', + 'type' => 'interval', + 'nothing' => __('None'), + 'nothing_value' => 0, + 'value' => $module_action_threshold, + ], + ], + ], + ], + ]; + } + + + /** + * Show actions alerts. + * + * @return string + */ + public function showActionAlerts():string + { + $filter_groups = implode(',', $this->groups); + + // Actions Correlated Alerts. + $actions_correlated = AlertCorrelation::getActionsAlert($this->id); + + $actions = []; + if (empty($actions_correlated) === false) { + // Actions Alerts. + $actions = $this->aC->getAlertsActions( + 'id_group IN ('.$filter_groups.')', + true + ); + + $actions = array_reduce( + $actions_correlated, + function ($carry, $item) use ($actions) { + if (isset($actions[$item['id_alert_action']]) === true) { + $carry[$item['id_alert_action']] = $actions[$item['id_alert_action']]; + } + + return $carry; + }, + [] + ); + } + + $modes = []; + $modes['firing'] = __('Firing'); + $modes['recovering'] = __('Recovering'); + + $form = [ + 'action' => $this->url, + 'method' => 'POST', + 'id' => 'filters_show_action_alerts', + + ]; + + $inputs = [ + [ + 'block_id' => 'filters_show_action_alerts', + 'class' => 'flex-row w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __( + 'Select the desired action and mode to view the Triggering fields for this action' + ), + ], + ], + ], + [ + 'class' => 'flex-row flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Action'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'firing_action_select', + 'name' => 'firing_action_select', + 'fields' => $actions, + 'selected' => -1, + 'nothing' => __('Select the action'), + 'nothing_value' => -1, + 'script' => 'firing_action_change( + \''.$this->id.'\', + \''.$this->ajaxController.'\', + \''.ui_get_full_url('ajax.php').'\' + );', + ], + ], + ], + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true, + true + ); + + return $output; + } + + + /** + * Create table Ajax Actions with field. + * + * @return void + */ + public function createActionTableAjax() + { + $firing_action = \get_parameter('firing_action', 0); + $id_alert = \get_parameter('id_alert', 0); + + if (empty($id_alert) === true || empty($firing_action) === true) { + return; + } + + // Retrieve RCMD object. + $this->getAlertCorrelationObject($id_alert); + $alert = $this->aC->get(); + + $fields = $this->aC->getAlertActionFields($firing_action); + + $table->class = 'info_table'; + $table->width = '100%'; + $table->head = []; + $table->data = []; + $table->size = []; + $table->size[0] = '10%'; + $table->size[1] = '30%'; + $table->size[2] = '30%'; + $table->style = []; + $table->style[3] = 'font-weight: bold;'; + + $table->title = __('Firing fields'); + $table->title .= ui_print_help_tip( + __('Fields passed to the command executed by this action when the alert is fired'), + true + ); + + $table->head[0] = __('Field'); + $table->head[0] .= ui_print_help_tip( + __('Fields configured on the command associated to the action'), + true + ); + $table->head[1] = __('Alerts fields'); + $table->head[1] .= ui_print_help_tip( + __('Triggering fields configured in Alerts'), + true + ); + $table->head[2] = __('Action fields'); + $table->head[2] .= ui_print_help_tip( + __('Triggering fields configured in action'), + true + ); + $table->head[3] = __('Executed on firing'); + $table->head[3] .= ui_print_help_tip( + __('Fields used on execution when the alert is fired'), + true + ); + + $firing_fields = []; + + $descriptions = json_decode($command['fields_descriptions'], true); + $action_values = json_decode($command['fields_values'], true); + + $i = 1; + foreach ($fields as $key => $value) { + $field = $key; + $data = []; + + // Data 0. + $data[0] = $key; + if (empty($data[0]) === false) { + $data[0] = ''.$data[0].'
'; + } + + $data[0] .= '
'; + $data[0] .= '('.sprintf(__('Field %s'), ($i)).')'; + + // Data 1. + $data[1] = $alert[$key]; + + // Data 2. + $data[2] = $value; + + // Data 3. + $data[3] = $alert[$key]; + if (empty($value) === false) { + $data[3] = $value; + } + + // UGLY. + $first_level = $template[$key]; + $second_level = $action[$key]; + if (empty($second_level) === false + || empty($first_level) === false + ) { + if (empty($second_level)) { + $table->cellclass[count($table->data)][1] = 'used_field'; + $table->cellclass[count($table->data)][2] = 'empty_field'; + } else { + $table->cellclass[count($table->data)][1] = 'overrided_field'; + $table->cellclass[count($table->data)][2] = 'used_field'; + } + } + + $table->data[] = $data; + $i++; + } + + die(html_print_table($table)); + + } + + + /** + * Clobal alerts view + * + * @return void + */ + public function viewAlertList() + { + // Header. + \ui_print_page_header( + __('Correlated alerts'), + 'images/gm_alerts.png', + false, + 'alert_correlation', + true + ); + + // TODO: Improve. + if ($this->page === 0) { + if (get_parameter('delete', 0) !== 0 + && $this->id !== 0 + ) { + // Delete correlated alert. + $this->getAlertCorrelationObject($this->id); + + $result = []; + if ((bool) $this->aC === true) { + $result = $this->aC->delete(); + } + + if ($result['error'] === true) { + echo ui_print_error_message($result['msg_error']); + } else { + echo ui_print_success_message(__('Alert succesfully deleted')); + } + } + + if (get_parameter('validate', 0) !== 0) { + // Validate correlated alert. + $alerts = get_parameter('alert', []); + + if (AlertCorrelation::validateAlerts($alerts) === true) { + echo ui_print_success_message(__('Alerts validated')); + } else { + echo ui_print_error_message( + __('Failed to process validation') + ); + } + } + } + + echo $this->viewAlertListForm(); + + echo $this->viewAlertListTable(); + + } + + + /** + * Global view filters. + * + * @return string + */ + public function viewAlertListForm():string + { + global $config; + + // TODO:XXX. + $search_string = (string) get_parameter('free_search', ''); + $search_group = (int) get_parameter('filter_id_group', 0); + + $form = [ + 'action' => $this->url, + 'method' => 'POST', + 'id' => 'filters_alert_list', + + ]; + + $inputs = [ + [ + 'block_id' => 'filters-alert-list', + 'class' => 'flex-row-vcenter flex-space-around w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Group'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'filter_id_group', + 'name' => 'filter_id_group', + 'fields' => users_get_groups_for_select( + $config['id_user'], + 'AR', + true, + true, + false + ), + 'selected' => $search_group, + ], + ], + [ + 'label' => __('Free Search'), + 'arguments' => [ + 'type' => 'text', + 'id' => 'free_search', + 'name' => 'free_search', + 'value' => $search_string, + 'return' => true, + ], + + ], + [ + 'arguments' => [ + 'button_class' => 'btn_filter', + 'attributes' => 'class="sub filter"', + 'type' => 'submit', + 'id' => 'filter_alert_list', + 'label' => __('Filter'), + 'width' => 'auto', + ], + ], + ], + + ], + ]; + + $output = $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ); + + $output = ui_toggle( + $output, + _('Filters'), + '', + '', + true, + true + ); + + return $output; + } + + + /** + * Global view table. + * + * @return void + */ + public function viewAlertListTable() + { + global $config; + + $filter['search_string'] = (string) get_parameter('free_search', ''); + $filter['search_group'] = (int) get_parameter('filter_id_group', 0); + + $alerts = AlertCorrelation::getAlerts($filter); + + // Initialize table. + $table = new stdClass(); + $table->width = '100%'; + $table->class = 'info_table'; + $table->id = 'sortable-alerts'; + $table->rowid = []; + + // Styles. + $table->style = []; + $table->style['checkbox'] = 'text-align: right'; + + $table->headstyle = []; + $table->headstyle['checkbox'] = 'text-align: right'; + + // Size. + $table->size = []; + $table->size[0] = '5%'; + $table->size[1] = '30%'; + $table->size[2] = '5%'; + $table->size[3] = '5%'; + $table->size[4] = '5%'; + $table->size[5] = '45%'; + $table->size['checkbox'] = '10px'; + + // Head. + $table->head = []; + $table->head[0] = __('Sort'); + $table->head[1] = __('Name'); + $table->head[2] = __('Group'); + $table->head[3] = __('Matched'); + $table->head[4] = __('Fired'); + $table->head[5] = __('Action'); + $table->head[6] = __('Options'); + $table->head['checkbox'] = $this->printInput( + [ + 'type' => 'checkbox', + 'id' => 'all_validate', + 'attributes' => 'class="chk" form="validation"', + ] + ); + + // Data. + $table->data = []; + if (empty($alerts) === false) { + foreach ($alerts as $alert) { + $table->cellclass[][6] = ' action_buttons mw180px'; + $table->rowid[] = 'sortable-alerts-'.$alert['id']; + // Sortable Items. + $data[0] = \html_print_image( + 'images/sortable.png', + true, + [ + 'title' => __('Sort elements'), + 'class' => 'handle-alerts', + ] + ); + + // Name alert with link. + $data[1] = ''; + $data[1] .= $alert['name']; + $data[1] .= ''; + + // Group Icon. + $data[2] = \ui_print_group_icon($alert['id_group'], true); + + // Status Icon. + $data[3] = ''; + $data[3] .= $this->addStatusIcon( + $alert['internal_counter'], + $alert['disabled'], + [ + 'fired' => 'Alert matched %d time(s)', + 'not_fired' => 'Alert not matched', + ] + ); + $data[3] .= ''; + + // Times fired. + $data[4] = ''; + $data[4] .= $this->addStatusIcon( + $alert['times_fired'], + $alert['standby'], + [ + 'fired' => 'Alert fired %d time(s)', + 'not_fired' => 'Alert not fired', + ] + ); + $data[4] .= ''; + + // Extract actions info for alert. + $actions = AlertCorrelation::getActionsAlert($alert['id']); + + $data[5] = ''; + } + + // Disbled Alert. + $data[6] = ''; + $data[6] .= $this->addDisabledIcon( + $alert['id'], + $alert['disabled'] + ); + $data[6] .= ''; + + // Standby Alert. + $data[6] .= ''; + $data[6] .= $this->addStandbyIcon( + $alert['id'], + $alert['standby'] + ); + $data[6] .= ''; + + // Add actions alerts. + $data[6] .= ' __('Add Actions'), + 'btn_text' => __('Ok'), + 'btn_cancel' => __('Cancel'), + 'url' => $this->ajaxController, + 'url_ajax' => ui_get_full_url('ajax.php'), + 'id' => $alert['id'], + ] + ); + $data[6] .= ')\'>'; + $data[6] .= html_print_input_image( + 'add_action', + 'images/add.png', + 1, + '', + true, + ['title' => __('Add Actions')] + ); + $data[6] .= ''; + + // Edit Alert. + $data[6] .= ''; + $data[6] .= html_print_input_image( + 'edit', + 'images/config.png', + 1, + '', + true, + ['title' => __('Edit')] + ); + $data[6] .= ''; + + // Delete Alert. + $data[6] .= ''; + $data[6] .= html_print_input_image( + 'del', + 'images/cross.png', + 1, + '', + true, + ['title' => __('Delete')] + ); + $data[6] .= ''; + + $data['checkbox'] = $this->printInput( + [ + 'type' => 'checkbox', + 'value' => $alert['id'], + 'name' => 'alert[]', + 'attributes' => 'class="chk" form="validation"', + ] + ); + + array_push($table->data, $data); + } + + echo html_print_table($table); + } else { + $return = ui_print_info_message( + [ + 'no_close' => true, + 'message' => __('There are no defined events alerts'), + ] + ); + } + + $form = [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url.'&page=1', + ], + 'inputs' => [ + [ + 'block_id' => 'buttons-alert-list', + 'class' => 'flex-row-vcenter flex-end w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Create'), + 'type' => 'submit', + 'attributes' => 'class="sub next"', + 'return' => true, + 'width' => 'auto', + ], + ], + ], + ], + ], + ]; + + $this->printForm( + [ + 'form' => [ + 'method' => 'POST', + 'action' => $this->url, + 'id' => 'validation', + ], + 'inputs' => [ + [ + 'block_id' => 'buttons-alert-list', + 'class' => 'flex-row-vcenter flex-end w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'arguments' => [ + 'type' => 'hidden', + 'name' => 'validate', + 'value' => 1, + ], + ], + [ + 'arguments' => [ + 'name' => 'submit', + 'label' => __('Validate'), + 'type' => 'submit', + 'attributes' => 'class="sub upd" ', + 'return' => true, + 'width' => 'auto', + ], + ], + ], + ], + ], + ] + ); + + $this->printForm($form); + + // Div for modal add actions. + echo ''; + echo ''; + + } + + + /** + * Icon status. + * + * @param integer $count Alert counter fired. + * @param integer $disabled Disabled alerts. + * @param array $titles Custom messages. + * + * @return string Icon. + */ + public function addStatusIcon( + $count, + $disabled=false, + $titles=[] + ) { + if (empty($titles) === true) { + $tiltes = [ + 'fired' => 'Alert fired %d time(s)', + 'not_fired' => 'Alert not fired', + ]; + } + + // Status Alerts. + $status = STATUS_ALERT_NOT_FIRED; + $title = ''; + if ($count > 0) { + $status = STATUS_ALERT_FIRED; + $title = __( + $titles['fired'], + $count + ); + } else if ($disabled > 0) { + $status = STATUS_ALERT_DISABLED; + $title = __('Alert disabled'); + } else { + $status = STATUS_ALERT_NOT_FIRED; + $title = __($titles['not_fired']); + } + + $output = ui_print_status_image($status, $title, true); + return $output; + } + + + /** + * Icon disabled or eneabled alert. + * + * @param integer $alert_id Alerts ID. + * @param integer $mode Disabled or enabled. + * + * @return string Icon. + */ + public function addDisabledIcon(int $alert_id, int $mode):string + { + $output = ''; + + // Disable alert. + $image_dis = 'images/lightbulb.png'; + $name_dis = 'disable'; + $title_dis = __('Disabled'); + $message_disabled = __('Are you sure you want to disable the alert'); + $message_disabled .= '?'; + if ((int) $mode === 1) { + $image_dis = 'images/lightbulb_off.png'; + $name_dis = 'enable'; + $title_dis = __('Enabled'); + $message_disabled = __('Are you sure you want to enable the alert'); + $message_disabled .= '?'; + } + + $output .= ' __('Disabled Alert'), + 'msg' => $message_disabled, + 'page' => $this->ajaxController, + 'url' => ui_get_full_url('ajax.php'), + 'id_alert' => $alert_id, + 'disabled' => $mode, + ] + ); + $output .= ')\'>'; + $output .= html_print_input_image( + $name_dis, + $image_dis, + 1, + '', + true, + ['title' => $title_dis] + ); + $output .= ''; + + return $output; + } + + + /** + * Icon standby alert. + * + * @param integer $alert_id Alerts ID. + * @param integer $mode Standby or play. + * + * @return string Icon. + */ + public function addStandbyIcon(int $alert_id, int $mode):string + { + $output = ''; + + // Standby alert. + $image_standby = 'images/bell.png'; + $name_standby = 'standby_off'; + $title_standby = __('Standby off'); + $message_standby = __('Are you sure you want to standby the alert'); + $message_standby .= '?'; + if ($mode === 1) { + $image_standby = 'images/bell_pause.png'; + $name_standby = 'standby_on'; + $title_standby = __('Standby on'); + $message_standby = __( + 'Are you sure you want to activate the alert' + ); + $message_standby .= '?'; + } + + $output .= ' __('Standby Alert'), + 'msg' => $message_standby, + 'page' => $this->ajaxController, + 'url' => ui_get_full_url('ajax.php'), + 'id_alert' => $alert_id, + 'standby' => $mode, + ] + ); + $output .= ')\'>'; + $output .= html_print_input_image( + $name_standby, + $image_standby, + 1, + '', + true, + ['title' => $title_standby] + ); + $output .= ''; + + return $output; + } + + + /** + * Add actions alerts. + * + * @param integer $id_alert Alerts ID. + * @param array $action Values create action. + * + * @return string li. + */ + public function addRowAction($id_alert, array $action):string + { + $output .= '
  • '; + $output .= \ui_print_truncate_text( + $action['name'], + GENERIC_SIZE_TEXT, + false + ); + $output .= ' ('; + if ((int) $action['fires_min'] === (int) $action['fires_max']) { + if ((int) $action['fires_min'] === 0) { + $output .= __('Always'); + } else { + $output .= __('On').' '.$action['fires_min']; + } + } else { + if ((int) $action['fires_min'] === 0) { + $output .= __('Until').' '; + $output .= $action['fires_max']; + } else { + $output .= __('From').' '; + $output .= $action['fires_min'].' '; + $output .= __('to').' '; + $output .= $action['fires_max']; + } + } + + if ((int) $action['module_action_threshold'] !== 0) { + $output .= ' '.__('Threshold').' '; + $output .= human_time_description_raw( + $action['module_action_threshold'] + ); + } + + $output .= ')'; + + // Delete actions alerts. + $output .= ' __('Delete Actions'), + 'msg' => __('Are you sure?'), + 'emptyli' => __('No associated actions'), + 'page' => $this->ajaxController, + 'url' => ui_get_full_url('ajax.php'), + 'id_action' => $action['id'], + 'id_alert' => $id_alert, + ] + ); + $output .= ')\'>'; + $output .= html_print_input_image( + 'delete', + 'images/cross.png', + 1, + '', + true, + ['title' => __('Delete')] + ); + $output .= ''; + $output .= '
  • '; + + return $output; + } + + + /** + * Add actions alerts AJAX. + * + * @return void. + */ + public function addRowActionAjax() + { + $id_alert = (int) \get_parameter('id_alert'); + $id_action = (int) \get_parameter('id_action'); + // Extract actions info for alert. + $action = AlertCorrelation::getActionAlert($id_alert, $id_action); + + die($this->addRowAction($id_alert, $action)); + } + + + /** + * Send form create actions AJAX. + * + * @return void. + */ + public function addAlertActionForm() + { + $extradata = json_decode( + io_safe_output(get_parameter('extradata')), + true + ); + + $form = [ + 'action' => '#', + 'id' => 'modal_form_add_actions', + 'onsubmit' => 'return false;', + 'class' => 'modal', + 'extra' => 'novalidate', + ]; + + $filter_groups = implode(',', $this->groups); + // TODO:XXX Change function alert correlation. + $actions = \alerts_get_alert_actions_filter( + true, + 'id_group IN ('.$filter_groups.')' + ); + + $inputs = [ + [ + 'class' => 'flex-row-vcenter flex-start w100p', + 'direct' => 1, + 'block_content' => [ + [ + 'label' => __('Actions'), + 'arguments' => [ + 'type' => 'select', + 'id' => 'actions_alert', + 'name' => 'actions_alert', + 'fields' => $actions, + ], + ], + [ + 'arguments' => [ + 'type' => 'hidden', + 'name' => 'id_alert', + 'value' => $extradata['id'], + ], + ], + ], + ], + [ + 'toggle' => true, + 'toggle_name' => 'Advanced', + 'block_content' => [ + [ + 'label' => __('Number of alerts match'), + ], + [ + 'label' => __('from'), + 'arguments' => [ + 'name' => 'fires_min', + 'id' => 'fires_min', + 'type' => 'number', + 'size' => 5, + ], + ], + [ + 'label' => __('to'), + 'arguments' => [ + 'name' => 'fires_max', + 'id' => 'fires_max', + 'type' => 'number', + 'size' => 5, + ], + ], + [ + 'label' => __('times in'), + 'arguments' => [ + 'name' => 'threshold', + 'type' => 'interval', + 'nothing' => __('None'), + 'nothing_value' => 0, + ], + ], + ], + ], + ]; + + die( + $this->printForm( + [ + 'form' => $form, + 'inputs' => $inputs, + ], + true + ) + ); + } + + + /** + * Add actions alerts AJAX. + * + * @return mixed. + */ + public function addAlertAction() + { + $id_alert = (int) \get_parameter('id_alert'); + $id_action = (int) \get_parameter('actions_alert'); + + if (isset($id_alert) === false + || isset($id_action) === false + || empty($id_alert) === true + || empty($id_action) === true + ) { + return false; + } + + $fires_min = (int) \get_parameter('fires_min', 0); + $fires_max = (int) \get_parameter('fires_max', 0); + $threshold = (int) \get_parameter('threshold'); + + $values = []; + $values['fires_min'] = $fires_min; + $values['fires_max'] = $fires_max; + $values['module_action_threshold'] = $threshold; + + // Retrieve alert correlation object. + $this->getAlertCorrelationObject($id_alert); + $result = $this->aC->setActionAlert($id_action, $values); + + $return = [ + 'error' => ($result['error'] === false) ? 0 : 1, + 'text' => [ + $result['msg_error'], + __('Successfully added action'), + ], + 'id_alert' => $id_alert, + 'id_action' => $result['result'], + 'url' => ui_get_full_url('ajax.php'), + 'page' => $this->ajaxController, + ]; + + exit(json_encode($return)); + } + + + /** + * Delete row action in global table. + * + * @return mixed + */ + public function deleteActionAlert() + { + $id_alert = (int) \get_parameter('id_alert'); + $id_action = (int) \get_parameter('id_action'); + + if (isset($id_alert) === false + || isset($id_action) === false + || empty($id_alert) === true + || empty($id_action) === true + ) { + return false; + } + + // Retrieve alert correlation object. + $this->getAlertCorrelationObject($id_alert); + $result = $this->aC->deleteActionAlert($id_action); + + $return = [ + 'error' => ($result['error'] === false) ? 0 : 1, + 'text' => [ + $result['msg_error'], + __('Successfully delete action'), + ], + ]; + + exit(json_encode($return)); + + } + + + /** + * Standby alert. + * + * @return void + */ + public function standByAlert() + { + $id_alert = (int) \get_parameter('id_alert'); + $standby = (int) \get_parameter('standby'); + + // Retrieve alert correlation object. + $this->getAlertCorrelationObject($id_alert); + $result = $this->aC->setStandbyAlert($standby); + + $html = ''; + if ($result['error'] === false) { + $html .= $this->addStandbyIcon( + $id_alert, + !$standby + ); + } + + exit($html); + } + + + /** + * Disabled alert. + * + * @return void + */ + public function disabledAlert() + { + $id_alert = (int) \get_parameter('id_alert'); + $disabled = (int) \get_parameter('disabled'); + + // Retrieve alert correlation object. + $this->getAlertCorrelationObject($id_alert); + $result = $this->aC->setDisabledAlert($disabled); + + $data = []; + if ($result['error'] === false) { + $data['disabled'] = $this->addDisabledIcon( + $id_alert, + !$disabled + ); + + $data['status'] = $this->addStatusIcon( + $this->aC->getTimesFired(), + !$disabled + ); + } + + exit(json_encode($data)); + } + + + /** + * Order column in bbdd. + * + * @return void + */ + public function orderAlert() + { + $new_order = \get_parameter('data', []); + + if (empty($new_order) === true) { + exit(); + } + + $new_order = array_reverse($new_order); + + $i = 0; + $updateOrder = []; + foreach ($new_order as $key => $value) { + $id = preg_replace('/sortable-alerts-/', '', $value); + + // Retrieve alert correlation object. + $this->getAlertCorrelationObject($id); + $this->aC->put(['order' => $i]); + + $i++; + } + + exit(); + } + + + /** + * Loads JS content. + * + * @return string JS content. + */ + public function loadJS() + { + // Javascript Alerts. + ui_require_javascript_file( + 'correlated_alerts', + ENTERPRISE_DIR.'/include/javascript/' + ); + + // Datepicker requirements. + ui_require_css_file('datepicker'); + ui_include_time_picker(); + ui_require_jquery_file( + 'ui.datepicker-'.get_user_language(), + 'include/javascript/i18n/' + ); + + $settingsDatePicker = json_encode( + [ + 'timeFormat' => TIME_FORMAT_JS, + 'timeOnlyTitle' => __('Choosetime'), + 'timeText' => __('Time'), + 'hourText' => __('Hour'), + 'minuteText' => __('Minute'), + 'secondText' => __('Second'), + 'currentText' => __('Now'), + 'closeText' => __('Close'), + 'dateFormat' => DATE_FORMAT_JS, + 'regional' => get_user_language(), + ] + ); + + ob_start(); + + // Javascript content. + ?> + + ", "<", ">=", "<=", "==", "!=", "REGEX", "NOT REGEX"]; + selectOnClick(obj, operators, "click-list-elements"); + break; + + case "variables": + // Common. + + var_type = getVariableType($(obj).attr("var_id")); + if ( + /group/.test(var_type) && + getDivs.innerText != "REGEX" && + getDivs.innerText != "NOT REGEX" + ) { + // Group content. + var groups = getGroupsSelect(); + selectOnClick(obj, groups, "click-list-elements variable"); + } else if ( + /severity/.test(var_type) && + getDivs.innerText != "REGEX" && + getDivs.innerText != "NOT REGEX" + ) { + // Severity content. + var severity = getSeveritySelect(); + selectOnClick(obj, severity, "click-list-elements variable"); + } else if ( + /event-type/.test(var_type) && + getDivs.innerText != "REGEX" && + getDivs.innerText != "NOT REGEX" + ) { + // Severity content. + var types = getEventTypesSelect(); + selectOnClick(obj, types, "click-list-elements variable"); + } else if ( + /event-tag/.test(var_type) && + getDivs.innerText != "REGEX" && + getDivs.innerText != "NOT REGEX" + ) { + // Severity content. + var tags = getTagsTypesSelect(); + selectOnClick(obj, tags, "click-list-elements variable"); + } else if (/event-agent/.test(var_type)) { + // Severity content. + var agents = getAgentsSelect(); + selectOnClick(obj, agents, "click-list-elements variable"); + } else if (/event-module/.test(var_type)) { + // Severity content. + var modules = getModulesSelect(); + selectOnClick(obj, modules, "click-list-elements variable"); + } else { + // Generic value. + obj.contentEditable = true; + $("#rules").sortable("disable"); + $(obj).addClass("inEdit"); + $(obj).focusout(function() { + save(this); + this.contentEditable = false; + if (getBlockState() == 0) { + $("#rules").sortable("enable"); + } + $(this).removeClass("inEdit"); + }); + } + + break; + + case "modifiers": + // TODO:XXX; + break; + + case "nexos": + var nexos = ["AND", "NAND", "OR", "NOR", "XOR", "NXOR"]; + selectOnClick(obj, nexos, "click-list-elements"); + + break; + + case "blocks": + // TODO:XXX; + break; + + default: + break; + } +} + +function selectOnClick(obj, data, classSelect) { + var select = $("").addClass(classSelect); + var input_value = $(obj).text(); + + $(obj).empty(); + $.each(data, function(index, value) { + var option; + if (value.id != undefined) { + option = $('').text( + value.title + ); + if (value.title == input_value) { + option.attr("selected", true); + } + } else { + option = $('').text(value); + if (value == input_value) { + option.attr("selected", true); + } + } + + select.append(option); + }); + + var f = function() { + var new_value = select.val(); + var new_text = select + .children() + .filter("option:selected") + .text(); + + if (/variable/.test($(obj).attr("class"))) { + updateStack($(obj).attr("var_id"), new_value); + } else { + updateStack($(obj).attr("id"), new_value); + } + + $(obj).empty(); + $(obj).append(new_text); + + if (/^fields-log/.test(new_value)) { + $(obj).addClass("log"); + $(obj).removeClass("event"); + } else if (/^fields-event/.test(new_value)) { + $(obj).addClass("event"); + $(obj).removeClass("log"); + } + }; + + select.change(f); + $(obj).focusout(f); + + $(obj).append(select); + + select.focus(); +} + +/** + * Add items to rules following gramatic rules. + * + * @param {Object} content DOM object dropped. + */ +function ruleBuilder(content) { + var stack = getStack(); + var id = $(content).attr("id"); + var latest = prevStack(stack); + var classType = $(content) + .attr("class") + .split(/\s+/)[0]; + + var item; + + item = { + type: classType, + id: id, + value: $(content).text(), + order: getBlockOrder() + }; + + // Control block start. + if (id == "block-start") { + if (getBlockState() == "1") { + console.error("Block already opened"); + return false; + } + setBlockState("1"); + + if (stack.length > 0) { + if (latest.type == "nexos") { + // Can add a block start after a nexus. + addStack(stack, item); + return true; + } + } + + if (stack.length == 0) { + addStack(stack, item); + return true; + } + } + + // Control block end. + if (id == "block-end") { + if (getBlockState() == "0") { + console.error("Block already closed"); + return false; + } + + if (stack.length > 0) { + // We can only close a block after add a variable. + if (latest.type == "variables") { + // Can add a block start after a nexus. + addStack(stack, item); + setBlockState("0"); + return true; + } + } + } + + // Control field. + if (classType == "fields") { + if ( + stack.length == 0 || + latest.id == "block-start" || + latest.type == "nexos" + ) { + // We can add a field after a block start or a nexo. + + if (checkItemBlock(item)) { + // We cannot repeat field in this block. + addStack(stack, item); + return true; + } + } + } + + // Control operator. + if (classType == "operators") { + if (latest.type == "fields" || latest.type == "variables") { + // We can add a operator after a field or a variable. + addStack(stack, item); + return true; + } + } + + // Control variables. + if (classType == "variables") { + if (latest.type == "operators" || latest.type == "modifiers") { + var var_id = getVariableID(); + // Localize item to handle edition. + $(content).attr("var-id", var_id); + item.var_id = var_id; + // We can add a operator after a field or a variable. + addStack(stack, item); + return true; + } + } + + // Control modifiers. + if (classType == "modifiers") { + // TODO: Could not be repeated per block!! + if (checkItemBlock(item)) { + if (latest.type == "variables") { + // We can add a operator after a field or a variable. + addStack(stack, item); + return true; + } + } + } + + // Control nexos. + if (classType == "nexos") { + if (latest.type == "variables" && getBlockState() == "0") { + // After a variable and at the end of a block (rule). + // Could be anything. + increaseBlockOrder(); + item.order = item.order + 1; + addStack(stack, item); + return true; + } + + if (latest.id == "block-end" && getBlockState() == "0") { + // After a block-end could be anything. + increaseBlockOrder(); + item.order += 1; + addStack(stack, item); + return true; + } + + if (getBlockState() == "1") { + // I'm inside a block. Coul only use AND nexos. + if (id == "nexo-and") { + addStack(stack, item); + return true; + } + } + } + + return false; +} +function uniqId() { + var id = Math.floor(Math.random() * 10000); + return "r" + id; +} + +function drop(ev) { + var stack = getStack(); + var new_rule = getBlockState() == 0; + + if (stack.length == 0) { + var div_e = document.createElement("div"); + div_e.setAttribute("id", getBlockOrder()); + div_e.setAttribute("name", "div_parent"); + div_e.setAttribute( + "class", + "div_parent target flex ui-sortable exclude-me" + ); + } + ev.preventDefault(); + $("#rules").removeClass("show"); + var content = ev.dataTransfer.getData("html"); + + // Source Element. + // Extract ID. + var id = $(content).attr("id"); + // Ensure rules. + if (ruleBuilder(content) != true) { + return; + } + + // Because we can add Nexos outside a rule, + // And '(' symbols to start them. But we need + // to add a 'div_e' only once. BUT if stack + // is empty, we must create a 'div_e' without + // NEXUS. + if (stack.length > 0) { + new_rule = new_rule && getBlockState() == 0; + } + + // Extract class type. + var classType = $(content) + .attr("class") + .split(/\s+/)[0]; + + // Remove Class. + content = $(content).removeClass(classType); + + // Change ID for non repeat and use variable change text. + content = $(content).attr("var_id", prevStack(getStack()).var_id); + + // Update general status. + updatePaneStatus(); + + // Add new id. + var uniq = uniqId(); + $(content) + .attr("item-id", $(content).attr("id")) + .attr("id", uniq) + .attr("order", getBlockOrder()) + .attr("ondblclick", "editMe(this,'" + classType + "')"); + + var data = document.createElement("span"); + + content = $(content).prop("outerHTML"); + data.innerHTML = content; + // If content nexo line break. + if (new_rule) { + // New rule. + div_e = document.createElement("div"); + div_e.setAttribute("id", getBlockOrder()); + div_e.setAttribute("name", "div_parent"); + div_e.setAttribute( + "class", + "div_parent target flex ui-sortable exclude-me" + ); + + document.getElementById(ev.target.id).appendChild(div_e); + } else { + div_e = document.getElementById(getBlockOrder()); + } + + div_e.append(data); +} + +/** + * Function to add automatically variable item when item selected equals modifiers or operators. + */ +function dropVariables() { + $("#rules").removeClass("show"); + // Source Element. + var content; + content = + '
    Double click to assign value
    '; + + // Extract ID. + var id = $(content).attr("id"); + // Ensure rules. + if (ruleBuilder(content) != true) { + return; + } + + // Extract clas type. + var classType = $(content) + .attr("class") + .split(/\s+/)[0]; + + // Remove Class. + content = $(content).removeClass(classType); + + // Change ID for non repeat and use variable change text. + content = $(content).attr("var_id", prevStack(getStack()).var_id); + // Update general status. + updatePaneStatus(); + + // TODO: UPDATE ITEM + // Add new id. + var uniq = uniqId(); + content = $(content).attr("id", uniq); + + content = $(content).prop("outerHTML"); + + // Create content. + var data = document.createElement("span"); + + content = $(content).prop("outerHTML"); + + var div_e = document.getElementById(getBlockOrder()); + // Add source element in content. + data.innerHTML = content; + div_e.appendChild(data); + // Add content to target. + document.getElementById("rules").appendChild(div_e); +} + +function add_alert_action(settings) { + load_modal({ + target: $("#modal-add-action-form"), + form: "modal_form_add_actions", + url: settings.url_ajax, + modal: { + title: settings.title, + cancel: settings.btn_cancel, + ok: settings.btn_text + }, + onshow: { + page: settings.url, + method: "addAlertActionForm", + extradata: { + id: settings.id + } + }, + onsubmit: { + page: settings.url, + method: "addAlertAction", + dataType: "json" + }, + ajax_callback: add_alert_action_acept, + idMsgCallback: "msg-add-action" + }); +} + +function add_alert_action_acept(data, idMsg) { + if (data.error === 1) { + console.log(data.text); + return; + } + + if ($("#emptyli-al-" + data.id_alert).length > 0) { + $("#emptyli-al-" + data.id_alert).remove(); + } + + $.ajax({ + method: "post", + url: data.url, + data: { + page: data.page, + method: "addRowActionAjax", + id_alert: data.id_alert, + id_action: data.id_action + }, + dataType: "html", + success: function(li) { + $(".ui-dialog-content").dialog("close"); + $("#ul-al-" + data.id_alert).append(li); + }, + error: function(error) { + console.log(error); + } + }); +} + +function delete_alert_action(settings) { + confirmDialog({ + title: settings.title, + message: settings.msg, + onAccept: function() { + $.ajax({ + method: "post", + url: settings.url, + data: { + page: settings.page, + method: "deleteActionAlert", + id_alert: settings.id_alert, + id_action: settings.id_action + }, + dataType: "json", + success: function(data) { + // Delete row table. + $( + "#li-al-" + settings.id_alert + "-act-" + settings.id_action + ).remove(); + + var num_row = $("#ul-al-" + settings.id_alert + " li").length; + if (num_row === 0) { + var emptyli = + "
  • " + + settings.emptyli + + "
  • "; + $("#ul-al-" + settings.id_alert).append(emptyli); + } + }, + error: function(error) { + console.log(error); + } + }); + } + }); +} + +function standby_alert(settings) { + confirmDialog({ + title: settings.title, + message: settings.msg, + onAccept: function() { + $.ajax({ + method: "post", + url: settings.url, + data: { + page: settings.page, + method: "standByAlert", + id_alert: settings.id_alert, + standby: settings.standby + }, + dataType: "html", + success: function(data) { + $("#standby-alert-" + settings.id_alert).empty(); + $("#standby-alert-" + settings.id_alert).append(data); + }, + error: function(error) { + console.log(error); + } + }); + } + }); +} + +function disabled_alert(settings) { + confirmDialog({ + title: settings.title, + message: settings.msg, + onAccept: function() { + $.ajax({ + method: "post", + url: settings.url, + data: { + page: settings.page, + method: "disabledAlert", + id_alert: settings.id_alert, + disabled: settings.disabled + }, + dataType: "json", + success: function(data) { + $("#disabled-alert-" + settings.id_alert).empty(); + $("#disabled-alert-" + settings.id_alert).append(data.disabled); + $("#status-alert-" + settings.id_alert).empty(); + $("#status-alert-" + settings.id_alert).append(data.status); + }, + error: function(error) { + console.log(error); + } + }); + } + }); +} + +function datetime_picker_callback(set) { + $("#text-time_from, #text-time_to").timepicker({ + showSecond: true, + timeFormat: set.timeFormat, + timeOnlyTitle: set.timeOnlyTitle, + timeText: set.timeText, + hourText: set.hourText, + minuteText: set.minuteText, + secondText: set.secondText, + currentText: set.currentText, + closeText: set.closeText + }); + + $("#text-date_from, #text-date_to").datepicker({ + dateFormat: set.dateFormat + }); + + $.datepicker.setDefaults($.datepicker.regional[set.regional]); +} + +function firing_action_change(idAlert, page, url) { + var action = $("#firing_action_select").val(); + $(".mode_table_firing").empty(); + if (action != -1) { + $("#firing").removeAttr("disabled"); + draw_table_firing(idAlert, action, page, url); + } + + return; +} + +function draw_table_firing(idAlert, action, page, url) { + $.ajax({ + method: "post", + url: url, + data: { + page: page, + method: "createActionTableAjax", + firing_action: action, + id_alert: idAlert + }, + dataType: "html", + success: function(data) { + $(".mode_table_firing").append(data); + }, + error: function(error) { + console.log(error); + } + }); +}