Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions inc/spbc-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ function spbc_admin_init()
// Settings
add_action('wp_ajax_spbc_settings__draw_elements', 'spbc_settings__draw_elements');
add_action('wp_ajax_spbc_scanner_tab__reload_accordion', 'spbc_field_scanner__show_accordion');
add_action('wp_ajax_spbc_scanner__get_accordions', 'spbc_scanner__get_accordions');

// Tabs requests handlers (React)
add_action('wp_ajax_spbct_get_tab_data', 'spbct_get_tab_data');
Expand Down
215 changes: 201 additions & 14 deletions inc/spbc-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use CleantalkSP\Security\LoginCollectingProtector;
use CleantalkSP\SpbctWP\API;
use CleantalkSP\SpbctWP\Cron as SpbcCron;
use CleantalkSP\SpbctWP\DTO\ReactDataDTO;
use CleantalkSP\SpbctWP\Escape;
use CleantalkSP\SpbctWP\Helpers\Arr;
use CleantalkSP\SpbctWP\Helpers\IP;
Expand Down Expand Up @@ -1715,12 +1716,6 @@ function spbc_field_scanner()
spbc_scanner__healLastScan();
}

echo '<div id="spbc_scan_accordion">';
if ( function_exists('spbc_scanner__hasCompletedScan') ? spbc_scanner__hasCompletedScan() : ! empty($spbc->data['scanner']['last_scan']) ) {
spbc_field_scanner__show_accordion(true);
}
echo '</div>';

echo '<br>';
echo spbc_field_scanner__log();

Expand Down Expand Up @@ -1816,12 +1811,8 @@ function spbc__analysyis_files_stats__get_data()
return $out;
}

function spbc_field_scanner__show_accordion($direct_call = false)
function spbc_scanner__accordion_catalog()
{
if ( ! $direct_call) {
spbc_check_ajax_referer('spbc_secret_nonce', 'security');
}

global $spbc;

//analysis log description
Expand Down Expand Up @@ -1977,6 +1968,17 @@ function spbc_field_scanner__show_accordion($direct_call = false)
),
);

return array($tables_files, $accordions_order);
}

function spbc_field_scanner__show_accordion($direct_call = false)
{
if ( ! $direct_call) {
spbc_check_ajax_referer('spbc_secret_nonce', 'security');
}

list($tables_files, $accordions_order) = spbc_scanner__accordion_catalog();

foreach ($accordions_order as $_category => $data) {
if ( isset($data['display']) && ! $data['display'] ) {
continue;
Expand Down Expand Up @@ -2045,6 +2047,191 @@ function spbc_field_scanner__show_accordion($direct_call = false)
}
}

/**
* Structured scan-result accordions for the React scanner tab.
* Same categories, tables and row actions as spbc_field_scanner__show_accordion().
*
* @param array $states Per-type view state: page, order_by, order, view_type, domain.
* @param string $open_panel Panel id whose rows should be built. Other panels return a count only.
* @return array
*/
function spbc_scanner__accordion_payload($states = array(), $open_panel = '')
{
global $spbc;

$feature_state = $spbc->feature_restrictions->getState($spbc, 'scanner');
if (false === $feature_state->is_active) {
return spbc_scanner__accordion_react_data(true, $feature_state->sanitizedReasonOutput(), array());
}

if ( function_exists('spbc_scanner__healLastScan') ) {
spbc_scanner__healLastScan();
}
$scan_in_progress = function_exists('spbc_scanner__isScannerIsInProgress') && spbc_scanner__isScannerIsInProgress();
if (
function_exists('spbc_scanner__hasCompletedScan') &&
! spbc_scanner__hasCompletedScan() &&
! $scan_in_progress
) {
return spbc_scanner__accordion_react_data(false, '', array());
}

list($tables_files, $accordions_order) = spbc_scanner__accordion_catalog();
$categories = array();

foreach ($accordions_order as $category_id => $data) {
if ( isset($data['display']) && ! $data['display'] ) {
continue;
}

$panels = array();
foreach ($data['types'] as $type_name) {
if ( ! isset($tables_files[$type_name]) ) {
continue;
}

if ( $type_name !== 'frontend_malware' && $type_name !== 'frontend_scan_results_approved' ) {
if ( empty(ScanResultsTableActions::getFilesByCategory($type_name, true)) ) {
continue;
}
}

$state = (isset($states[$type_name]) && is_array($states[$type_name])) ? $states[$type_name] : array();
$view_type = $type_name;
if (
$type_name === 'outbound_links' &&
isset($state['view_type']) &&
$state['view_type'] === 'links'
) {
$view_type = 'links';
}

$args = spbc_scanner__table_args_for_state($view_type, $state);
$args['id'] = 'spbc_tbl__scanner_' . $view_type;
$args['type'] = $view_type;

$table = new ListTable($args);
$build_rows = ($open_panel !== '' && $open_panel === $type_name);
$table->getData($build_rows);

$if_empty = array_key_exists('if_empty_items', $args) ? $args['if_empty_items'] : null;
if ( $if_empty === false && (int) $table->items_total === 0 && $view_type === $type_name ) {
continue;
}

$danger = (
($type_name === 'critical' && ! empty($spbc->data['display_scanner_warnings']['critical']))
|| ($type_name === 'frontend_malware' && ! empty($spbc->data['display_scanner_warnings']['frontend']))
|| ($type_name === 'analysis_log' && ! empty($spbc->data['display_scanner_warnings']['analysis']))
|| ($type_name === 'oscron' && ! empty($spbc->data['display_scanner_warnings']['oscron']))
|| ($type_name === 'db_trigger' && ! empty($spbc->data['display_scanner_warnings']['db_triggers']))
);

$exported = $table->exportForReact();
if ( ! $build_rows ) {
$exported['summary'] = true;
$exported['rows'] = array();
$exported['empty_html'] = '';
}
$exported['panel_id'] = $type_name;
$exported['title'] = ucwords(str_replace('_', ' ', $type_name));
$exported['description_html'] = $tables_files[$type_name];
$exported['danger'] = $danger;
$exported['count'] = (int) $table->items_total;
$panels[] = $exported;
}

if ( $panels ) {
$categories[] = array(
'id' => $category_id,
'title' => $data['category_description'],
'panels' => $panels,
);
}
}

return spbc_scanner__accordion_react_data(false, '', $categories);
}

/**
* Pack scan-result accordions into the React tab DTO.
*
* @param bool $restricted Scanner feature is inactive.
* @param string $reason_html Restriction notice HTML.
* @param array $categories Accordion categories.
* @return array
*/
function spbc_scanner__accordion_react_data($restricted, $reason_html, $categories)
{
$data = ReactDataDTO::getDefaultArray();
$data['flags']['restricted'] = (bool) $restricted;
$data['strings']['reason_html'] = (string) $reason_html;
$data['objects']['categories'] = $categories;

$dto = new ReactDataDTO($data);

return $dto->getArray();
}

/**
* Apply pagination, sort and domain filter requested by the React table.
*
* @param string $type
* @param array $state
* @return array
*/
function spbc_scanner__table_args_for_state($type, $state)
{
if ( $type === 'links' && ! empty($state['domain']) ) {
$_POST['domain'] = sanitize_text_field($state['domain']);
}

$args = spbc_list_table__get_args_by_type($type);

if ( ! isset($args['pagination']) || ! is_array($args['pagination']) ) {
$args['pagination'] = array('page' => 1, 'per_page' => SPBC_LAST_ACTIONS_TO_VIEW);
}

$page = 1;
if ( isset($state['page']) && $state['page'] !== '' && $state['page'] !== null ) {
$page = max(1, (int) $state['page']);
}
$args['pagination']['page'] = $page;
Comment thread
svedge marked this conversation as resolved.
Resolved
// Cure log reads $_POST['page']. Set it for this table, including page 1,
// so a previous panel's page cannot leak into the next callback.
$_POST['page'] = $page;
Comment thread
svedge marked this conversation as resolved.
Resolved

if ( ! empty($state['order_by']) ) {
$order_by = (string) $state['order_by'];
$order = (isset($state['order']) && strtolower((string) $state['order']) === 'desc') ? 'desc' : 'asc';
$allowed = ! empty($args['sortable']) ? $args['sortable'] : array();
if ( preg_match('/^[a-z0-9_]+$/i', $order_by) === 1 && in_array($order_by, $allowed, true) ) {
/** @psalm-var non-empty-string $order_by */
$args['order_by'] = array($order_by => $order);
}
}

return $args;
}

/**
* AJAX: scan result accordions for React.
*/
function spbc_scanner__get_accordions()
{
spbc_check_ajax_referer('spbc_secret_nonce', 'security');

$raw = isset($_POST['tables']) ? wp_unslash($_POST['tables']) : '';
$states = is_string($raw) ? json_decode($raw, true) : array();
if ( ! is_array($states) ) {
$states = array();
}

$open_panel = isset($_POST['open_panel']) ? sanitize_key(wp_unslash($_POST['open_panel'])) : '';

wp_send_json_success(spbc_scanner__accordion_payload($states, $open_panel));
}

/**
* Return arguments for ListTable::__constructor()
*
Expand Down Expand Up @@ -2400,16 +2587,16 @@ function spbc_list_table__get_args_by_type($table_type)
. '</div>',
'columns' => array(
'cb' => array('heading' => '<input type=checkbox>', 'class' => 'check-column', 'width_percent' => 2),
'about_trigger' => array( 'heading' => 'About trigger', 'width_percent' => 30 ), // name, table, time, action
'about_trigger' => array( 'heading' => 'About trigger', 'primary' => true, 'width_percent' => 30 ), // name, table, time, action
'code' => array( 'heading' => 'Code', 'width_percent' => 43 ),
'signature' => array( 'heading' => 'Signature', 'width_percent' => 10 ),
'analysis_status' => array( 'heading' => 'Verdict', 'width_percent' => 15 ),
),
'actions' => array(
'delete' => array('name' => 'Delete',),
'delete-trigger' => array('name' => __('Delete', 'security-malware-firewall'),),
),
'bulk_actions' => array(
'delete' => array('name' => 'Delete',),
'delete-trigger' => array('name' => __('Delete', 'security-malware-firewall'),),
),
);
break;
Expand Down
36 changes: 33 additions & 3 deletions js/public/spbct-react-bundle.js

Large diffs are not rendered by default.

Loading
Loading