admin_url( 'admin-ajax.php' ),
)
);
}
add_action( 'admin_enqueue_scripts', 'wpvulnerability_admin_enqueue_scripts' );
/**
* Processes the form submission for the WPVulnerability plugin settings in a multisite network admin context.
*
* Checks if the current request is a submission from the WPVulnerability settings page.
* Verifies the security nonce to prevent CSRF attacks. If the verification fails or if the request
* is not from a network admin or the admin dashboard, the function will halt execution and display an error.
* Otherwise, it sanitizes and updates the plugin settings, reschedules any relevant wp-cron events,
* and registers a settings error to notify the user that the information has been updated.
*
* @since 3.0.0
* @return void
*/
function wpvulnerability_process_network_config_forms() {
// Only process config forms that have the wpvulnerability_submit button.
// Other action forms (delete logs, reset, etc.) have their own handlers.
if ( ! isset( $_POST['wpvulnerability_submit'] ) ) {
return;
}
if ( isset( $_GET['page'] ) && 'wpvulnerability-options' === $_GET['page'] ) {
if ( check_admin_referer( 'wpvulnerability_nonce', 'wpauto_nonce' ) ) {
if ( ! current_user_can( 'manage_network_options' ) ) {
return;
}
if ( isset( $_POST['wpvulnerability-config'] ) ) {
$post_config = filter_input( INPUT_POST, 'wpvulnerability-config', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( ! is_array( $post_config ) ) {
$post_config = array();
}
$wpvulnerability_sanitized_values = wpvulnerability_sanitize_config( $post_config );
update_site_option( 'wpvulnerability-config', $wpvulnerability_sanitized_values );
unset( $wpvulnerability_sanitized_values );
add_settings_error(
'wpvulnerability-messages',
'wpvulnerability-updated',
__( 'Settings saved.', 'wpvulnerability' ),
'success'
);
}
if ( isset( $_POST['wpvulnerability-analyze'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
$wpvulnerability_sanitized_values = array(
'core' => 0,
'plugins' => 0,
'themes' => 0,
'php' => 0,
'apache' => 0,
'nginx' => 0,
'mariadb' => 0,
'mysql' => 0,
'imagemagick' => 0,
'curl' => 0,
'memcached' => 0,
'redis' => 0,
'sqlite' => 0,
);
$wpvulnerability_analyze_raw = (array) wp_unslash( $_POST['wpvulnerability-analyze'] );
$wpvulnerability_values = array();
foreach ( $wpvulnerability_analyze_raw as $v ) {
$wpvulnerability_values[] = sanitize_text_field( is_scalar( $v ) ? (string) $v : '' );
}
foreach ( $wpvulnerability_values as $data ) {
switch ( $data ) {
case 'core':
$wpvulnerability_sanitized_values['core'] = 1;
break;
case 'plugins':
$wpvulnerability_sanitized_values['plugins'] = 1;
break;
case 'themes':
$wpvulnerability_sanitized_values['themes'] = 1;
break;
case 'php':
$wpvulnerability_sanitized_values['php'] = 1;
break;
case 'apache':
$wpvulnerability_sanitized_values['apache'] = 1;
break;
case 'nginx':
$wpvulnerability_sanitized_values['nginx'] = 1;
break;
case 'mariadb':
$wpvulnerability_sanitized_values['mariadb'] = 1;
break;
case 'mysql':
$wpvulnerability_sanitized_values['mysql'] = 1;
break;
case 'imagemagick':
$wpvulnerability_sanitized_values['imagemagick'] = 1;
break;
case 'curl':
$wpvulnerability_sanitized_values['curl'] = 1;
break;
case 'memcached':
$wpvulnerability_sanitized_values['memcached'] = 1;
break;
case 'redis':
$wpvulnerability_sanitized_values['redis'] = 1;
break;
case 'sqlite':
$wpvulnerability_sanitized_values['sqlite'] = 1;
break;
}
}
update_site_option(
'wpvulnerability-analyze',
array(
'core' => $wpvulnerability_sanitized_values['core'],
'plugins' => $wpvulnerability_sanitized_values['plugins'],
'themes' => $wpvulnerability_sanitized_values['themes'],
'php' => $wpvulnerability_sanitized_values['php'],
'apache' => $wpvulnerability_sanitized_values['apache'],
'nginx' => $wpvulnerability_sanitized_values['nginx'],
'mariadb' => $wpvulnerability_sanitized_values['mariadb'],
'mysql' => $wpvulnerability_sanitized_values['mysql'],
'imagemagick' => $wpvulnerability_sanitized_values['imagemagick'],
'curl' => $wpvulnerability_sanitized_values['curl'],
'memcached' => $wpvulnerability_sanitized_values['memcached'],
'redis' => $wpvulnerability_sanitized_values['redis'],
'sqlite' => $wpvulnerability_sanitized_values['sqlite'],
)
);
unset( $wpvulnerability_sanitized_values );
add_settings_error(
'wpvulnerability-messages',
'wpvulnerability-updated',
__( 'Settings saved.', 'wpvulnerability' ),
'success'
);
}
}
}
}
add_action( 'admin_init', 'wpvulnerability_process_network_config_forms' );
/**
* Process action form submissions (delete logs, reset, test email, etc.).
*
* @since 4.3.0
* @return void
*/
function wpvulnerability_process_network_action_forms() {
/**
* Reset the data
*
* @since 3.0.0
*/
if ( isset( $_POST['wpvulnerability_reset'] ) && check_admin_referer( 'wpvulnerability_reset_action', 'wpvulnerability_reset_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
// Calls the reset function.
wpvulnerability_update_database_data();
set_transient( 'wpvulnerability_message_manual_success', __( 'Data from source has been reloaded.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reload data.', 'wpvulnerability' ), 10 );
}
}
/**
* Send an test email
*
* @since 3.0.0
*/
if ( isset( $_POST['wpvulnerability_email'] ) && check_admin_referer( 'wpvulnerability_email_action', 'wpvulnerability_email_nonce' ) ) {
if ( ! function_exists( 'wpvulnerability_execute_notification' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-process.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-notifications.php';
}
// Calls the notifications function, forced.
if ( current_user_can( 'manage_network_options' ) ) {
$wpmail = wpvulnerability_execute_notification( true );
if ( $wpmail ) {
set_transient( 'wpvulnerability_message_manual_success', __( 'Test email has been sent.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'Test email has failed. Please, check your email settings.', 'wpvulnerability' ), 10 );
}
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to send test emails.', 'wpvulnerability' ), 10 );
}
}
/**
* Repairs scheduled cron events across the network.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_repair_cron'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
$wpvulnerability_settings = get_site_option( 'wpvulnerability-config', array() );
$cron_config = is_array( $wpvulnerability_settings ) ? $wpvulnerability_settings : array();
wpvulnerability_repair_network_cron_events( $cron_config );
set_transient( 'wpvulnerability_message_manual_success', __( 'WPVulnerability cron events have been repaired across the network.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to repair cron events.', 'wpvulnerability' ), 10 );
}
}
/**
* Delete all stored API logs across the network.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_delete_logs'] ) && check_admin_referer( 'wpvulnerability_delete_logs_action', 'wpvulnerability_delete_logs_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
wpvulnerability_delete_all_logs();
set_transient( 'wpvulnerability_message_manual_success', __( 'All logs have been deleted.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to delete logs.', 'wpvulnerability' ), 10 );
}
}
/**
* Fully resets plugin data, settings, and cached API content across the network.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_delete_on_uninstall'] ) && check_admin_referer( 'wpvulnerability_uninstall_action', 'wpvulnerability_uninstall_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
$wpvulnerability_settings = get_site_option( 'wpvulnerability-config', array() );
if ( ! is_array( $wpvulnerability_settings ) ) {
$wpvulnerability_settings = array();
}
$wpvulnerability_settings['delete_on_uninstall'] = isset( $_POST['delete_on_uninstall'] ) ? 1 : 0;
update_site_option( 'wpvulnerability-config', $wpvulnerability_settings );
}
}
if ( isset( $_POST['wpvulnerability_full_reset'] ) && check_admin_referer( 'wpvulnerability_full_reset_action', 'wpvulnerability_full_reset_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
wpvulnerability_reset_plugin_data();
set_transient( 'wpvulnerability_message_manual_success', __( 'WPVulnerability has been reset to defaults and reloaded.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reset WPVulnerability.', 'wpvulnerability' ), 10 );
}
}
/**
* Handles debug action: Clear all caches.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_debug_clear_caches'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
if ( ! function_exists( 'wpvulnerability_debug_clear_all_caches' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php';
}
wpvulnerability_debug_clear_all_caches();
set_transient( 'wpvulnerability_message_manual_success', __( 'All caches have been cleared.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to clear caches.', 'wpvulnerability' ), 10 );
}
}
/**
* Handles debug action: Reset signatures.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_debug_reset_signatures'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
if ( ! function_exists( 'wpvulnerability_debug_reset_signatures' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php';
}
wpvulnerability_debug_reset_signatures();
set_transient( 'wpvulnerability_message_manual_success', __( 'Plugin and theme signatures have been reset.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to reset signatures.', 'wpvulnerability' ), 10 );
}
}
/**
* Handles debug action: Export debug info.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_debug_export'] ) && check_admin_referer( 'wpvulnerability_debug_action', 'wpvulnerability_debug_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
if ( ! function_exists( 'wpvulnerability_debug_export_info' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php';
}
$wpvulnerability_debug_info = wpvulnerability_debug_export_info();
$wpvulnerability_filename = 'wpvulnerability-debug-' . gmdate( 'Y-m-d-His' ) . '.json';
header( 'Content-Type: application/json' );
header( 'Content-Disposition: attachment; filename="' . $wpvulnerability_filename . '"' );
header( 'Content-Length: ' . strlen( $wpvulnerability_debug_info ) );
echo $wpvulnerability_debug_info; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
exit;
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to export debug information.', 'wpvulnerability' ), 10 );
}
}
/**
* Handles debug action: Run update database now.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_run_update'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
wpvulnerability_update_database_data();
set_transient( 'wpvulnerability_message_manual_success', __( 'Database update has been executed.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to run database updates.', 'wpvulnerability' ), 10 );
}
}
/**
* Handles debug action: Run notification now.
*
* @since 4.3.0
*/
if ( isset( $_POST['wpvulnerability_run_notification'] ) && check_admin_referer( 'wpvulnerability_cron_action', 'wpvulnerability_cron_nonce' ) ) {
if ( current_user_can( 'manage_network_options' ) ) {
if ( ! function_exists( 'wpvulnerability_execute_notification' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-core.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-plugins.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-themes.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-software.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-process.php';
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-notifications.php';
}
$wpvulnerability_result = wpvulnerability_execute_notification( true );
if ( $wpvulnerability_result ) {
set_transient( 'wpvulnerability_message_manual_success', __( 'Notification has been sent.', 'wpvulnerability' ), 10 );
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'Notification sending failed.', 'wpvulnerability' ), 10 );
}
} else {
set_transient( 'wpvulnerability_message_manual_error', __( 'You do not have permission to send notifications.', 'wpvulnerability' ), 10 );
}
}
}
add_action( 'admin_init', 'wpvulnerability_process_network_action_forms' );
/**
* Create the WP-Admin options page
* This function generates the HTML output for the WPVulnerability settings page in the WP-Admin.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_create_admin_page() {
if ( ! current_user_can( 'manage_network_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wpvulnerability' ) );
}
?>
' . esc_html( is_scalar( $wpvulnerability_message_manual_success ) ? (string) $wpvulnerability_message_manual_success : '' ) . '
';
delete_transient( 'wpvulnerability_message_manual_success' );
unset( $wpvulnerability_message_manual_success );
}
$wpvulnerability_message_manual_error = get_transient( 'wpvulnerability_message_manual_error' );
if ( $wpvulnerability_message_manual_error ) {
echo '' . esc_html( is_scalar( $wpvulnerability_message_manual_error ) ? (string) $wpvulnerability_message_manual_error : '' ) . '
';
delete_transient( 'wpvulnerability_message_manual_error' );
unset( $wpvulnerability_message_manual_error );
}
?>
$tab_data ) {
$tab_label = isset( $tab_data['label'] ) ? $tab_data['label'] : '';
$is_active = ( $tab_slug === $current_tab );
$tab_url = add_query_arg(
array(
'page' => 'wpvulnerability-options',
'tab' => $tab_slug,
),
network_admin_url( 'settings.php' )
);
$tab_class = 'nav-tab wpvulnerability-tab-link';
if ( $is_active ) {
$tab_class .= ' nav-tab-active';
}
?>
tabindex="-1"
>
> An associative array of tab slugs and their labels.
*/
function wpvulnerability_get_network_admin_tabs() {
$tabs = array(
'notifications' => array(
'label' => __( 'Notifications', 'wpvulnerability' ),
),
'analysis' => array(
'label' => __( 'Analysis', 'wpvulnerability' ),
),
'logs' => array(
'label' => __( 'Logs', 'wpvulnerability' ),
),
'security' => array(
'label' => __( 'Security', 'wpvulnerability' ),
),
'tools' => array(
'label' => __( 'Tools', 'wpvulnerability' ),
),
);
// Add Debug tab only if WP_DEBUG is enabled.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
$tabs['debug'] = array(
'label' => __( 'Debug', 'wpvulnerability' ),
);
}
$tabs['about'] = array(
'label' => __( 'About', 'wpvulnerability' ),
);
return $tabs;
}
/**
* Determines the active multisite admin tab.
*
* @since 4.1.2
*
* @param array> $tabs Registered multisite admin tabs.
*
* @return string The active tab slug.
*/
function wpvulnerability_get_current_network_admin_tab( $tabs ) {
$tab_keys = array_keys( $tabs );
$default = reset( $tab_keys );
$tab_filter = filter_input( INPUT_GET, 'tab', FILTER_SANITIZE_SPECIAL_CHARS );
if ( $tab_filter ) {
$tab_filter = sanitize_key( $tab_filter );
}
if ( $tab_filter && isset( $tabs[ $tab_filter ] ) ) {
return $tab_filter;
}
return $default ? $default : 'notifications';
}
/**
* Renders the requested multisite admin tab content.
*
* @since 4.1.2
*
* @param string $tab Tab slug to render.
*
* @return void
*/
function wpvulnerability_render_network_admin_tab( $tab ) {
switch ( $tab ) {
case 'analysis':
wpvulnerability_render_network_admin_tab_analysis();
break;
case 'logs':
wpvulnerability_render_network_admin_tab_logs();
break;
case 'security':
wpvulnerability_render_network_admin_tab_security();
break;
case 'tools':
wpvulnerability_render_network_admin_tab_tools();
break;
case 'debug':
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
wpvulnerability_render_network_admin_tab_debug();
}
break;
case 'about':
wpvulnerability_render_network_admin_tab_about();
break;
case 'notifications':
default:
wpvulnerability_render_network_admin_tab_notifications();
break;
}
}
/**
* Outputs the Notifications tab contents for the multisite settings screen.
*
* @since 4.1.2
*
* @return void
*/
function wpvulnerability_render_network_admin_tab_notifications() {
$wpvulnerability_settings = get_site_option( 'wpvulnerability-config', array() );
if ( ! is_array( $wpvulnerability_settings ) ) {
$wpvulnerability_settings = array();
}
$defaults = array(
'cache' => 12,
'period' => 'weekly',
'day' => 'monday',
'hour' => 0,
'minute' => 0,
'emails' => '',
'slack_webhook' => '',
'teams_webhook' => '',
'discord_webhook' => '',
'telegram_bot_token' => '',
'telegram_chat_id' => '',
'notify' => array(
'email' => 'y',
'slack' => 'n',
'teams' => 'n',
'discord' => 'n',
'telegram' => 'n',
),
);
$wpvulnerability_settings = wp_parse_args( $wpvulnerability_settings, $defaults );
// Normalize notify settings.
if ( ! is_array( $wpvulnerability_settings['notify'] ) ) {
$wpvulnerability_settings['notify'] = $defaults['notify'];
} else {
$wpvulnerability_settings['notify'] = wp_parse_args( $wpvulnerability_settings['notify'], $defaults['notify'] );
}
$wpvulnerability_settings['notify'] = wpvulnerability_normalize_notify_settings( $wpvulnerability_settings['notify'] );
$email_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['email'] );
$slack_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['slack'] );
$teams_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['teams'] );
$discord_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['discord'] );
$telegram_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['telegram'] );
// Check if cache is forced.
$forced_cache = null;
$cache_options = array( 1, 6, 12, 24 );
if ( defined( 'WPVULNERABILITY_CACHE_HOURS' ) ) {
$forced_cache = (int) WPVULNERABILITY_CACHE_HOURS;
if ( ! in_array( $forced_cache, $cache_options, true ) ) {
$cache_options[] = $forced_cache;
sort( $cache_options, SORT_NUMERIC );
}
}
$current_cache = null !== $forced_cache ? $forced_cache : (int) $wpvulnerability_settings['cache'];
$admin_email = get_site_option( 'admin_email' );
?>
array(
'label' => __( 'WordPress Components', 'wpvulnerability' ),
'items' => array(
'core' => array(
'label' => __( 'WordPress Core', 'wpvulnerability' ),
'icon' => 'š',
),
'plugins' => array(
'label' => __( 'Plugins', 'wpvulnerability' ),
'icon' => 'š§©',
),
'themes' => array(
'label' => __( 'Themes', 'wpvulnerability' ),
'icon' => 'šØ',
),
),
),
'software' => array(
'label' => __( 'Software & Languages', 'wpvulnerability' ),
'items' => array(
'php' => array(
'label' => __( 'PHP', 'wpvulnerability' ),
'icon' => 'š',
),
),
),
'webservers' => array(
'label' => __( 'Web Servers', 'wpvulnerability' ),
'items' => array(
'apache' => array(
'label' => __( 'Apache HTTPD', 'wpvulnerability' ),
'icon' => 'šŖ¶',
),
'nginx' => array(
'label' => __( 'nginx', 'wpvulnerability' ),
'icon' => 'š©',
),
),
),
'databases' => array(
'label' => __( 'Databases', 'wpvulnerability' ),
'items' => array(
'mariadb' => array(
'label' => __( 'MariaDB', 'wpvulnerability' ),
'icon' => 'š¬',
),
'mysql' => array(
'label' => __( 'MySQL', 'wpvulnerability' ),
'icon' => 'š¬',
),
'sqlite' => array(
'label' => __( 'SQLite', 'wpvulnerability' ),
'icon' => 'š¾',
),
),
),
'tools' => array(
'label' => __( 'Additional Tools', 'wpvulnerability' ),
'items' => array(
'imagemagick' => array(
'label' => __( 'ImageMagick', 'wpvulnerability' ),
'icon' => 'š¼ļø',
),
'curl' => array(
'label' => __( 'curl', 'wpvulnerability' ),
'icon' => 'š',
),
'memcached' => array(
'label' => __( 'memcached', 'wpvulnerability' ),
'icon' => 'ā”',
),
'redis' => array(
'label' => __( 'Redis', 'wpvulnerability' ),
'icon' => 'š“',
),
),
),
);
?>
$total_pages ) {
$current_page = $total_pages;
}
$logs = wpvulnerability_get_api_logs( $logs_per_page, $current_page );
$logs_page_url = add_query_arg(
array(
'page' => 'wpvulnerability-options',
'tab' => 'logs',
'logs_per_page' => $logs_per_page,
'log_page' => $current_page,
),
network_admin_url( 'settings.php' )
);
$requested_log = isset( $_GET['log'] ) ? absint( (int) wp_unslash( is_string( $_GET['log'] ) ? $_GET['log'] : '' ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$view_log = null;
$log_error = '';
$pagination = '';
if ( $total_pages > 1 ) {
$pagination_base = remove_query_arg(
array( 'log', 'log_page' ),
$logs_page_url
);
$pagination = paginate_links(
array(
'base' => add_query_arg( 'log_page', '%#%', $pagination_base ),
'format' => '',
'current' => $current_page,
'total' => $total_pages,
'prev_text' => __( '« Previous', 'wpvulnerability' ),
'next_text' => __( 'Next »', 'wpvulnerability' ),
'type' => 'list',
)
);
}
if ( $requested_log > 0 ) {
$nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( is_string( $_GET['_wpnonce'] ) ? $_GET['_wpnonce'] : '' ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( $nonce && wp_verify_nonce( $nonce, 'wpvulnerability_view_log_' . $requested_log ) ) {
$view_log = wpvulnerability_get_api_log( $requested_log );
if ( ! $view_log ) {
$log_error = __( 'Log entry not found or has been removed.', 'wpvulnerability' );
}
} else {
$log_error = __( 'Unable to load the requested log entry.', 'wpvulnerability' );
}
}
?>
|
|
|
|
|
|
'wpvulnerability-options',
'tab' => 'logs',
'log' => $log->ID,
'logs_per_page' => $logs_per_page,
'log_page' => $current_page,
),
network_admin_url( 'settings.php' )
);
$view_url = wp_nonce_url( $view_url, 'wpvulnerability_view_log_' . $log->ID );
?>
|
__( 'Plugins', 'wpvulnerability' ),
'themes' => __( 'Themes', 'wpvulnerability' ),
'php' => __( 'PHP', 'wpvulnerability' ),
'apache' => __( 'Apache HTTPD', 'wpvulnerability' ),
'nginx' => __( 'nginx', 'wpvulnerability' ),
'mariadb' => __( 'MariaDB', 'wpvulnerability' ),
'mysql' => __( 'MySQL', 'wpvulnerability' ),
'imagemagick' => __( 'ImageMagick', 'wpvulnerability' ),
'curl' => __( 'curl', 'wpvulnerability' ),
'memcached' => __( 'memcached', 'wpvulnerability' ),
'redis' => __( 'Redis', 'wpvulnerability' ),
'sqlite' => __( 'SQLite', 'wpvulnerability' ),
);
?>
' . esc_html( $formatted_datetime ) . '' );
restore_previous_locale();
?>
'CVE',
'euvd' => 'EUVD',
'jvn' => 'JVN',
'patchstack' => 'Patchstack',
'wpscan' => 'WPScan',
'wordfence' => 'Wordfence',
);
if ( ! empty( $sources_stat ) ) :
?>
:
';
foreach ( $options as $hours ) {
printf(
'',
esc_attr( (string) $hours ),
selected( $current, $hours, false ),
esc_html(
sprintf(
/* translators: %d: number of hours */
_n( '%d hour', '%d hours', $hours, 'wpvulnerability' ),
$hours
)
)
);
}
echo '';
if ( null !== $forced_cache ) {
printf(
'',
esc_attr( (string) $current )
);
}
printf(
'%2$s
',
esc_url( 'https://www.wpvulnerability.com/plugin/#cache-duration' ),
esc_html__( 'Read more if you want to force the cache time.', 'wpvulnerability' )
);
}
/**
* Print the settings header information for the analyze section.
*
* @since 3.3.0
*
* @return void
*/
function wpvulnerability_admin_section_analyze() {
// Output the header information for the analyze section.
esc_html_e( 'Configure and save these settings to hide vulnerabilities.', 'wpvulnerability' );
}
/**
* Print when to send the vulnerability scan emails.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_admin_period_callback() {
// Get the saved plugin settings.
$wpvulnerability_settings = get_site_option( 'wpvulnerability-config', array() );
if ( ! is_array( $wpvulnerability_settings ) ) {
$wpvulnerability_settings = array();
}
$defaults = array(
'period' => 'weekly',
'day' => 'monday',
'hour' => 0,
'minute' => 0,
);
$wpvulnerability_settings = wp_parse_args( $wpvulnerability_settings, $defaults );
?>
'y',
'slack' => 'n',
'teams' => 'n',
);
if ( ! isset( $wpvulnerability_settings['notify'] ) || ! is_array( $wpvulnerability_settings['notify'] ) ) {
$wpvulnerability_settings['notify'] = $defaults;
} else {
$wpvulnerability_settings['notify'] = wp_parse_args( $wpvulnerability_settings['notify'], $defaults );
}
$wpvulnerability_settings['notify'] = wpvulnerability_normalize_notify_settings( $wpvulnerability_settings['notify'] );
$email_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['email'] );
$slack_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['slack'] );
$teams_enabled = wpvulnerability_is_yes( $wpvulnerability_settings['notify']['teams'] );
?>
0 ) {
if ( ( wpvulnerability_analyze_filter( 'core' ) && $core_count > 0 ) ||
( wpvulnerability_analyze_filter( 'php' ) && $php_count > 0 ) ||
$total_vulnerabilities > 5 ) {
$status_class = 'wpvuln-status-critical';
$status_icon = 'ā';
/* translators: %d: number of vulnerabilities */
$status_text = sprintf( _n( '%d Critical Issue Found', '%d Critical Issues Found', $total_vulnerabilities, 'wpvulnerability' ), $total_vulnerabilities );
} else {
$status_class = 'wpvuln-status-warning';
$status_icon = 'ā ';
/* translators: %d: number of vulnerabilities */
$status_text = sprintf( _n( '%d Issue Found', '%d Issues Found', $total_vulnerabilities, 'wpvulnerability' ), $total_vulnerabilities );
}
}
// Get last check time.
$raw_core_cache = get_site_option( 'wpvulnerability-core-cache', '' );
$core_cache = json_decode( is_string( $raw_core_cache ) ? $raw_core_cache : '', true );
$last_check_text = __( 'Never checked', 'wpvulnerability' );
if ( $core_cache && is_numeric( $core_cache ) ) {
$cache_hours = wpvulnerability_cache_hours();
$last_check_time = $core_cache - ( $cache_hours * 3600 );
$time_diff = time() - $last_check_time;
if ( $time_diff < 3600 ) {
$minutes_ago = (int) floor( $time_diff / 60 );
/* translators: %d: number of minutes */
$last_check_text = sprintf( _n( '%d minute ago', '%d minutes ago', $minutes_ago, 'wpvulnerability' ), $minutes_ago );
} else {
$hours_ago = (int) floor( $time_diff / 3600 );
/* translators: %d: number of hours */
$last_check_text = sprintf( _n( '%d hour ago', '%d hours ago', $hours_ago, 'wpvulnerability' ), $hours_ago );
}
}
// Status badge.
echo '';
echo esc_html( $status_text );
echo '
';
// Meta information.
echo '';
// If no vulnerabilities, show empty state.
if ( 0 === $total_vulnerabilities ) {
echo '';
echo '
ā
';
echo '
' . esc_html( __( 'No vulnerabilities detected', 'wpvulnerability' ) ) . '
';
echo '
' . esc_html( __( 'Your site is up to date and secure', 'wpvulnerability' ) ) . '
';
echo '
';
} else {
// WordPress Components section.
echo '' . esc_html( __( 'WordPress Components', 'wpvulnerability' ) ) . '
';
// Core.
if ( wpvulnerability_analyze_filter( 'core' ) ) {
$badge_class = $core_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure';
$badge_icon = $core_count > 0 ? 'ā' : 'ā';
echo '';
echo '
 . 'assets/icon-wordpress.svg)
';
echo '
' . esc_html( __( 'WordPress Core', 'wpvulnerability' ) ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $core_count ) . '';
echo '
';
}
// Plugins.
if ( wpvulnerability_analyze_filter( 'plugins' ) ) {
$badge_class = $plugins_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure';
$badge_icon = $plugins_count > 0 ? 'ā' : 'ā';
echo '';
echo '
 . 'assets/icon-plugin.svg)
';
echo '
' . esc_html( __( 'Plugins', 'wpvulnerability' ) ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $plugins_count ) . '';
echo '
';
if ( $plugins_count > 0 ) {
echo '';
echo wpvulnerability_list_plugins(); // phpcs:ignore
echo '
';
}
}
// Themes.
if ( wpvulnerability_analyze_filter( 'themes' ) ) {
$badge_class = $themes_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure';
$badge_icon = $themes_count > 0 ? 'ā' : 'ā';
echo '';
echo '
 . 'assets/icon-theme.svg)
';
echo '
' . esc_html( __( 'Themes', 'wpvulnerability' ) ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $themes_count ) . '';
echo '
';
if ( $themes_count > 0 ) {
echo '';
echo wpvulnerability_list_themes(); // phpcs:ignore
echo '
';
}
}
// Server Software section.
$php_version = wpvulnerability_detect_php();
$webserver = wpvulnerability_detect_webserver();
$sqlserver = wpvulnerability_detect_sqlserver();
$show_server_section = false;
// Check if any server software is detected.
if ( ( wpvulnerability_analyze_filter( 'php' ) && $php_version ) ||
( isset( $webserver['id'] ) && isset( $webserver['version'] ) ) ||
( isset( $sqlserver['id'] ) && isset( $sqlserver['version'] ) ) ||
wpvulnerability_get_software_version( 'imagemagick' ) ||
wpvulnerability_get_software_version( 'curl' ) ||
wpvulnerability_get_software_version( 'memcached' ) ||
wpvulnerability_get_software_version( 'redis' ) ||
wpvulnerability_get_software_version( 'sqlite' ) ) {
$show_server_section = true;
}
if ( $show_server_section ) {
echo '' . esc_html( __( 'Server Software', 'wpvulnerability' ) ) . '
';
echo '';
// PHP.
if ( wpvulnerability_analyze_filter( 'php' ) && $php_version ) {
$badge_class = $php_count > 0 ? 'wpvuln-badge-critical' : 'wpvuln-badge-secure';
$badge_icon = $php_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-php.svg)
';
echo '
PHP ' . esc_html( $php_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $php_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'php' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
// Web server (Apache/nginx).
if ( isset( $webserver['id'] ) && isset( $webserver['version'] ) ) {
if ( 'apache' === $webserver['id'] && wpvulnerability_analyze_filter( 'apache' ) ) {
$badge_class = $apache_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $apache_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-apache.svg)
';
echo '
Apache ' . esc_html( $webserver['version'] ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $apache_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'apache' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
} elseif ( 'nginx' === $webserver['id'] && wpvulnerability_analyze_filter( 'nginx' ) ) {
$badge_class = $nginx_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $nginx_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-nginx.svg)
';
echo '
nginx ' . esc_html( $webserver['version'] ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $nginx_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'nginx' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
}
// Database (MariaDB/MySQL).
if ( isset( $sqlserver['id'] ) && isset( $sqlserver['version'] ) ) {
if ( 'mariadb' === $sqlserver['id'] && wpvulnerability_analyze_filter( 'mariadb' ) ) {
$badge_class = $mariadb_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $mariadb_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-mariadb.svg)
';
echo '
MariaDB ' . esc_html( $sqlserver['version'] ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $mariadb_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'mariadb' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
} elseif ( 'mysql' === $sqlserver['id'] && wpvulnerability_analyze_filter( 'mysql' ) ) {
$badge_class = $mysql_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $mysql_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-mysql.svg)
';
echo '
MySQL ' . esc_html( $sqlserver['version'] ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $mysql_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'mysql' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
}
// ImageMagick.
$imagemagick_version = wpvulnerability_get_software_version( 'imagemagick' );
if ( $imagemagick_version && wpvulnerability_analyze_filter( 'imagemagick' ) ) {
$badge_class = $imagemagick_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $imagemagick_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-imagemagick.svg)
';
echo '
ImageMagick ' . esc_html( $imagemagick_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $imagemagick_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'imagemagick' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
// curl.
$curl_version = wpvulnerability_get_software_version( 'curl' );
if ( $curl_version && wpvulnerability_analyze_filter( 'curl' ) ) {
$badge_class = $curl_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $curl_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-curl.svg)
';
echo '
curl ' . esc_html( $curl_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $curl_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'curl' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
// memcached.
$memcached_version = wpvulnerability_get_software_version( 'memcached' );
if ( $memcached_version && wpvulnerability_analyze_filter( 'memcached' ) ) {
$badge_class = $memcached_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $memcached_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-memcached.svg)
';
echo '
memcached ' . esc_html( $memcached_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $memcached_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'memcached' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
// Redis.
$redis_version = wpvulnerability_get_software_version( 'redis' );
if ( $redis_version && wpvulnerability_analyze_filter( 'redis' ) ) {
$badge_class = $redis_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $redis_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-redis.svg)
';
echo '
Redis ' . esc_html( $redis_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $redis_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'redis' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
// SQLite.
$sqlite_version = wpvulnerability_get_software_version( 'sqlite' );
if ( $sqlite_version && wpvulnerability_analyze_filter( 'sqlite' ) ) {
$badge_class = $sqlite_count > 0 ? 'wpvuln-badge-warning' : 'wpvuln-badge-secure';
$badge_icon = $sqlite_count > 0 ? 'ā' : 'ā';
echo '
';
echo '
 . 'assets/icon-sqlite.svg)
';
echo '
SQLite ' . esc_html( $sqlite_version ) . '';
echo '
' . esc_html( $badge_icon ) . ' ' . esc_html( (string) $sqlite_count ) . '';
echo wp_kses(
wpvulnerability_eol_badge_html( 'sqlite' ),
array(
'span' => array(
'class' => array(),
'title' => array(),
),
)
);
echo '
';
}
echo '
';
}
}
// Footer links.
echo '';
}
/**
* Created a widget in the WordPress dashboard with vulnerability info.
*
* @since 2.2.0
*
* @return void
*/
function wpvulnerability_admin_dashboard() {
if ( wpvulnerability_capabilities() ) {
wp_add_dashboard_widget(
'wpvulnerability',
__( 'WPVulnerability Status', 'wpvulnerability' ),
'wpvulnerability_admin_dashboard_content',
null,
null,
'side',
'high'
);
}
}
add_action( 'wp_network_dashboard_setup', 'wpvulnerability_admin_dashboard' );
/**
* Strictly sanitizes the main configuration (emails and periods).
*
* @since 2.0.0
*
* @param array $input Input values.
* @return array Sanitized values.
*/
function wpvulnerability_sanitize_config( $input ) {
$defaults = array(
'emails' => null,
'period' => 'weekly',
'day' => 'monday',
'hour' => 0,
'minute' => 0,
'cache' => 12,
'log_retention' => 0,
'notify' => array(
'email' => 'n',
'slack' => 'n',
'teams' => 'n',
),
'slack_webhook' => '',
'teams_webhook' => '',
);
$current_values = get_site_option( 'wpvulnerability-config', array() );
if ( ! is_array( $current_values ) ) {
$current_values = array();
}
$sanitized = $current_values;
// Emails (comma-separated list).
if ( isset( $input['emails'] ) ) {
$emails_raw = explode( ',', is_scalar( $input['emails'] ) ? (string) $input['emails'] : '' );
$sanitized_emails = array();
foreach ( $emails_raw as $email ) {
$email = sanitize_email( trim( (string) $email ) );
if ( is_email( $email ) ) {
$sanitized_emails[] = $email;
}
}
$sanitized['emails'] = count( $sanitized_emails ) ? implode( ',', $sanitized_emails ) : null;
}
// Period (daily, weekly, never).
$allowed_periods = array( 'daily', 'weekly', 'never' );
if ( isset( $input['period'] ) && in_array( $input['period'], $allowed_periods, true ) ) {
$sanitized['period'] = $input['period'];
}
// Day of week for weekly schedule.
if ( isset( $input['day'] ) ) {
$day = strtolower( is_scalar( $input['day'] ) ? (string) $input['day'] : '' );
$valid = array( 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' );
$sanitized['day'] = in_array( $day, $valid, true ) ? $day : 'monday';
}
// Time (hour and minute).
if ( isset( $input['hour'] ) ) {
$hour = is_scalar( $input['hour'] ) ? (int) $input['hour'] : 0;
$sanitized['hour'] = max( 0, min( 23, $hour ) );
}
if ( isset( $input['minute'] ) ) {
$minute = is_scalar( $input['minute'] ) ? (int) $input['minute'] : 0;
$sanitized['minute'] = max( 0, min( 59, $minute ) );
}
// Cache expiration.
if ( isset( $input['cache'] ) ) {
$cache = is_scalar( $input['cache'] ) ? (int) $input['cache'] : 0;
$sanitized['cache'] = in_array( $cache, array( 1, 6, 12, 24 ), true ) ? $cache : 12;
}
if ( isset( $input['log_retention'] ) ) {
$retention = is_scalar( $input['log_retention'] ) ? (int) $input['log_retention'] : 0;
if ( in_array( $retention, wpvulnerability_get_log_retention_values(), true ) ) {
$sanitized['log_retention'] = $retention;
}
}
// Notification methods.
if ( isset( $input['notify'] ) && is_array( $input['notify'] ) ) {
$notify_raw = (array) wp_unslash( $input['notify'] );
$notify_input = array();
foreach ( $notify_raw as $k => $v ) {
$notify_input[ (string) $k ] = sanitize_text_field( is_scalar( $v ) ? (string) $v : '' );
}
$sanitized['notify'] = wpvulnerability_normalize_notify_settings( $notify_input );
}
// Webhooks.
if ( isset( $input['slack_webhook'] ) ) {
$slack_url = trim( is_scalar( $input['slack_webhook'] ) ? (string) $input['slack_webhook'] : '' );
if ( '' !== $slack_url ) {
$validated_slack = wpvulnerability_validate_webhook_url(
$slack_url,
array( 'hooks.slack.com' )
);
if ( '' === $validated_slack ) {
add_settings_error(
'wpvulnerability-config',
'invalid-slack-webhook',
__( 'Invalid Slack webhook URL. Must be a valid HTTPS URL from hooks.slack.com', 'wpvulnerability' ),
'error'
);
$sanitized['slack_webhook'] = '';
} else {
$sanitized['slack_webhook'] = $validated_slack;
}
} else {
$sanitized['slack_webhook'] = '';
}
}
if ( isset( $input['teams_webhook'] ) ) {
$teams_url = trim( is_scalar( $input['teams_webhook'] ) ? (string) $input['teams_webhook'] : '' );
if ( '' !== $teams_url ) {
$validated_teams = wpvulnerability_validate_webhook_url(
$teams_url,
array( 'office.com', 'office365.com', 'api.hooks.microsoft.com' )
);
if ( '' === $validated_teams ) {
add_settings_error(
'wpvulnerability-config',
'invalid-teams-webhook',
__( 'Invalid Microsoft Teams webhook URL. Must be a valid HTTPS URL from office.com, office365.com, or api.hooks.microsoft.com', 'wpvulnerability' ),
'error'
);
$sanitized['teams_webhook'] = '';
} else {
$sanitized['teams_webhook'] = $validated_teams;
}
} else {
$sanitized['teams_webhook'] = '';
}
}
if ( isset( $input['discord_webhook'] ) ) {
$discord_url = trim( is_scalar( $input['discord_webhook'] ) ? (string) $input['discord_webhook'] : '' );
if ( '' !== $discord_url ) {
$validated_discord = wpvulnerability_validate_webhook_url(
$discord_url,
array( 'discord.com', 'discordapp.com' )
);
if ( '' === $validated_discord ) {
add_settings_error(
'wpvulnerability-config',
'invalid-discord-webhook',
__( 'Invalid Discord webhook URL. Must be a valid HTTPS URL from discord.com or discordapp.com', 'wpvulnerability' ),
'error'
);
$sanitized['discord_webhook'] = '';
} else {
$sanitized['discord_webhook'] = $validated_discord;
}
} else {
$sanitized['discord_webhook'] = '';
}
}
if ( isset( $input['telegram_bot_token'] ) ) {
$telegram_bot_token = sanitize_text_field( trim( is_scalar( $input['telegram_bot_token'] ) ? (string) $input['telegram_bot_token'] : '' ) );
if ( '' !== $telegram_bot_token ) {
if ( ! preg_match( '/^\d+:[A-Za-z0-9_-]+$/', $telegram_bot_token ) ) {
add_settings_error(
'wpvulnerability-config',
'invalid-telegram-token',
__( 'Invalid Telegram bot token format. Must be like: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11', 'wpvulnerability' ),
'error'
);
$sanitized['telegram_bot_token'] = '';
} else {
$sanitized['telegram_bot_token'] = $telegram_bot_token;
}
} else {
$sanitized['telegram_bot_token'] = '';
}
}
if ( isset( $input['telegram_chat_id'] ) ) {
$sanitized['telegram_chat_id'] = sanitize_text_field( trim( is_scalar( $input['telegram_chat_id'] ) ? (string) $input['telegram_chat_id'] : '' ) );
}
$sanitized = wp_parse_args( $sanitized, $defaults );
// Schedule notification based on sanitized values.
wpvulnerability_schedule_notification_event( $sanitized );
return $sanitized;
}
/**
* Strictly sanitizes the analysis options (booleans).
*
* @since 3.3.0
*
* @param array $input Input values.
* @return array Sanitized values.
*/
function wpvulnerability_sanitize_analyze( $input ) {
$components = array(
'core',
'plugins',
'themes',
'php',
'apache',
'nginx',
'mariadb',
'mysql',
'imagemagick',
'curl',
'memcached',
'redis',
'sqlite',
);
$sanitized = array();
foreach ( $components as $component ) {
$sanitized[ $component ] = isset( $input[ $component ] ) ? (bool) $input[ $component ] : false;
$constant = 'WPVULNERABILITY_HIDE_' . strtoupper( (string) $component );
if ( defined( $constant ) && constant( $constant ) ) {
$sanitized[ $component ] = true;
}
}
return $sanitized;
}
/**
* Initializes the WP-Admin settings page for the WP Vulnerability plugin.
*
* @since 2.0.0
*
* @return void
*/
function wpvulnerability_admin_init() {
// Register the plugin settings to be saved in the database.
register_setting(
'admin_wpvulnerability_settings',
'wpvulnerability-config',
array(
'sanitize_callback' => 'wpvulnerability_sanitize_config',
'default' => array(),
'show_in_rest' => false,
'type' => 'array',
)
);
// Add a section to the settings page.
add_settings_section(
'admin_wpvulnerability_settings',
__( 'Receive vulnerability notifications', 'wpvulnerability' ),
'wpvulnerability_admin_section_notifications',
'wpvulnerability-config'
);
// Add a field to the settings page for the cache expiration time.
add_settings_field(
'wpvulnerability_cache',
__( 'Cache expiration time', 'wpvulnerability' ),
'wpvulnerability_admin_cache_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Add a field to the settings page for the notification period.
add_settings_field(
'wpvulnerability_period',
__( 'How often you want to receive notifications', 'wpvulnerability' ),
'wpvulnerability_admin_period_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Add a field for notification methods.
add_settings_field(
'wpvulnerability_notify',
__( 'Where do you want to receive notifications?', 'wpvulnerability' ),
'wpvulnerability_admin_notify_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Add a field to the settings page for the email addresses.
add_settings_field(
'wpvulnerability_emails',
__( 'Email addresses to notify (separated by commas)', 'wpvulnerability' ),
'wpvulnerability_admin_emails_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Add a field for the Slack webhook.
add_settings_field(
'wpvulnerability_slack_webhook',
__( 'Slack webhook URL', 'wpvulnerability' ),
'wpvulnerability_admin_slack_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Add a field for the Teams webhook.
add_settings_field(
'wpvulnerability_teams_webhook',
__( 'Teams webhook URL', 'wpvulnerability' ),
'wpvulnerability_admin_teams_callback',
'wpvulnerability-config',
'admin_wpvulnerability_settings'
);
// Register the plugin settings to be saved in the database.
register_setting(
'admin_wpvulnerability_analyze',
'wpvulnerability-analyze',
array(
'sanitize_callback' => 'wpvulnerability_sanitize_analyze',
'default' => array(),
'show_in_rest' => false,
'type' => 'array',
)
);
// Add a section to the settings page.
add_settings_section(
'admin_wpvulnerability_analyze',
__( 'Vulnerabilities to hide', 'wpvulnerability' ),
'wpvulnerability_admin_section_analyze',
'wpvulnerability-analyze'
);
// Add a field to the settings page for analyzing components.
add_settings_field(
'wpvulnerability_analyze',
__( 'What do you want to hide?', 'wpvulnerability' ),
'wpvulnerability_admin_analyze_callback',
'wpvulnerability-analyze',
'admin_wpvulnerability_analyze'
);
}
add_action( 'admin_init', 'wpvulnerability_admin_init' );
/**
* Outputs the Security tab contents for the multisite network admin.
*
* Reuses the single-site security display functions since the functionality
* is identical for both single-site and multisite contexts.
*
* @since 4.3.0
*
* @return void
*/
function wpvulnerability_render_network_admin_tab_security() {
?>
__( 'Standard (Hybrid Detection)', 'wpvulnerability' ),
'strict' => __( 'Strict (Extensions Only)', 'wpvulnerability' ),
'disabled' => __( 'Disabled (No Detection)', 'wpvulnerability' ),
);
$mode_label = isset( $mode_labels[ $security_mode ] ) ? $mode_labels[ $security_mode ] : $security_mode;
?>
post_date ) ), time() )
)
);
?>
security configuration documentation for details.', 'wpvulnerability' ) ),
esc_url( 'https://www.wpvulnerability.com/plugin/#security-configuration' )
);
?>
__( 'ImageMagick', 'wpvulnerability' ),
'redis' => __( 'Redis', 'wpvulnerability' ),
'memcached' => __( 'Memcached', 'wpvulnerability' ),
'sqlite' => __( 'SQLite', 'wpvulnerability' ),
);
$detections = array();
foreach ( array_keys( $components ) as $component ) {
$detection = null;
// Do not run detection for components hidden via the analysis settings or
// a WPVULNERABILITY_HIDE_* constant: they must not trigger shell_exec.
if ( ! wpvulnerability_analyze_filter( $component ) ) {
continue;
}
switch ( $component ) {
case 'imagemagick':
$detection = wpvulnerability_detect_imagemagick();
break;
case 'redis':
$detection = wpvulnerability_detect_redis();
break;
case 'memcached':
$detection = wpvulnerability_detect_memcached();
break;
case 'sqlite':
$detection = wpvulnerability_detect_sqlite();
break;
}
$detections[ $component ] = $detection;
}
$method_labels = array(
'imagick_extension' => __( 'Imagick Extension', 'wpvulnerability' ),
'redis_extension' => __( 'Redis Extension', 'wpvulnerability' ),
'memcached_extension' => __( 'Memcached Extension', 'wpvulnerability' ),
'memcache_extension' => __( 'Memcache Extension', 'wpvulnerability' ),
'sqlite3_extension' => __( 'SQLite3 Extension', 'wpvulnerability' ),
'pdo_sqlite' => __( 'PDO SQLite', 'wpvulnerability' ),
'shell_exec' => __( 'Shell Command', 'wpvulnerability' ),
'binary_exists' => __( 'Binary Check', 'wpvulnerability' ),
'none' => __( 'Not Detected', 'wpvulnerability' ),
);
?>
|
|
|
|
$detection ) : ?>
|
' . esc_html__( 'Not detected', 'wpvulnerability' ) . '';
}
?>
|
|
0 ) {
$reliability_class = 'low';
if ( $reliability >= 80 ) {
$reliability_class = '';
} elseif ( $reliability >= 50 ) {
$reliability_class = 'medium';
}
?>
%
ā
|
|
|
|
|
|
|
post_content, true );
if ( ! is_array( $log_data ) ) {
$log_data = array();
}
if ( empty( $log_data ) ) {
continue;
}
$log_component = isset( $log_data['component'] ) && is_string( $log_data['component'] ) ? $log_data['component'] : '';
$log_command = isset( $log_data['command'] ) && is_string( $log_data['command'] ) ? $log_data['command'] : '';
$log_reason = isset( $log_data['reason'] ) && is_string( $log_data['reason'] ) ? $log_data['reason'] : '';
$log_user = isset( $log_data['user'] ) && is_string( $log_data['user'] ) ? $log_data['user'] : '';
$log_output = isset( $log_data['output'] ) && is_string( $log_data['output'] ) ? $log_data['output'] : '';
$log_success = ! empty( $log_data['success'] );
?>
|
post_date ) ), time() )
)
);
?>
|
|
|
|
|
50 ) : ?>
...
ā
|
';
esc_html_e( 'You do not have permission to access this page.', 'wpvulnerability' );
echo '
';
return;
}
// Load debug functions if not already loaded.
if ( ! function_exists( 'wpvulnerability_debug_get_system_info' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php';
}
?>
__( 'Invalid nonce.', 'wpvulnerability' ) ) );
}
// Check permissions.
if ( ! current_user_can( 'manage_network_options' ) ) {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'wpvulnerability' ) ) );
}
// Get component.
$component = isset( $_POST['component'] ) ? sanitize_key( is_string( $_POST['component'] ) ? $_POST['component'] : '' ) : '';
if ( empty( $component ) ) {
wp_send_json_error( array( 'message' => __( 'No component specified.', 'wpvulnerability' ) ) );
}
// Load debug functions.
if ( ! function_exists( 'wpvulnerability_debug_test_api_component' ) ) {
require_once WPVULNERABILITY_PLUGIN_PATH . '/wpvulnerability-debug.php';
}
// Test API.
$wpvulnerability_result = wpvulnerability_debug_test_api_component( $component );
wp_send_json_success( $wpvulnerability_result );
}
add_action( 'wp_ajax_wpvulnerability_test_api', 'wpvulnerability_ajax_network_test_api' );
/**
* Renders Section 1: System Information.
*
* @since 4.3.0
*
* @return void
*/
function wpvulnerability_render_debug_section_system_info() {
$system_info = wpvulnerability_debug_get_system_info();
// Extract typed sub-arrays from the mixed return value.
$si_wordpress = isset( $system_info['wordpress'] ) && is_array( $system_info['wordpress'] ) ? $system_info['wordpress'] : array();
$si_php = isset( $system_info['php'] ) && is_array( $system_info['php'] ) ? $system_info['php'] : array();
$si_database = isset( $system_info['database'] ) && is_array( $system_info['database'] ) ? $system_info['database'] : array();
$si_webserver = isset( $system_info['webserver'] ) && is_array( $system_info['webserver'] ) ? $system_info['webserver'] : array();
$si_debug = isset( $system_info['debug'] ) && is_array( $system_info['debug'] ) ? $system_info['debug'] : array();
$si_wp_version = isset( $si_wordpress['version'] ) && is_scalar( $si_wordpress['version'] ) ? (string) $si_wordpress['version'] : '';
$si_multisite = ! empty( $si_wordpress['multisite'] );
$si_language = isset( $si_wordpress['language'] ) && is_scalar( $si_wordpress['language'] ) ? (string) $si_wordpress['language'] : '';
$si_php_version = isset( $si_php['version'] ) && is_scalar( $si_php['version'] ) ? (string) $si_php['version'] : '';
$si_extensions = isset( $si_php['extensions'] ) && is_array( $si_php['extensions'] ) ? $si_php['extensions'] : array();
$si_memory = isset( $si_php['memory'] ) && is_array( $si_php['memory'] ) ? $si_php['memory'] : array();
$si_mem_limit = isset( $si_memory['limit'] ) && is_scalar( $si_memory['limit'] ) ? (string) $si_memory['limit'] : '';
$si_db_type = isset( $si_database['type'] ) && is_scalar( $si_database['type'] ) ? (string) $si_database['type'] : '';
$si_db_version = isset( $si_database['version'] ) && is_scalar( $si_database['version'] ) ? (string) $si_database['version'] : '';
$si_webserver_s = isset( $si_webserver['software'] ) && is_scalar( $si_webserver['software'] ) ? (string) $si_webserver['software'] : '';
$si_wp_debug = ! empty( $si_debug['wp_debug'] );
$si_debug_log = ! empty( $si_debug['wp_debug_log'] );
$si_log_file = isset( $si_debug['log_file'] ) && is_array( $si_debug['log_file'] ) ? $si_debug['log_file'] : array();
?>