Files
argus-wp-defence/admin/class-argus-admin.php
T
root df0f2fccb8 ARGUS WordPress Defence 1.0.0 — first production release
Automatic WordPress security: local firewall, malware and file-integrity
scanning, vulnerability protection, quarantine, scheduled backups, an
optional page cache, and automatic global threat intelligence.

See README.md for installation, update, and uninstall instructions.
2026-08-09 13:40:16 +00:00

629 lines
35 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Argus_Admin {
public static function init() {
add_action( 'admin_menu', array( __CLASS__, 'register_menu' ) );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
add_action( 'admin_head', array( __CLASS__, 'hide_settings_from_sidebar' ) );
add_action( 'wp_ajax_argus_wpd_live_feed', array( __CLASS__, 'ajax_live_feed' ) );
add_action( 'admin_post_argus_wpd_download_backup', array( __CLASS__, 'handle_backup_download' ) );
add_action( 'admin_init', array( __CLASS__, 'handle_firewall_actions' ) );
}
public static function handle_firewall_actions() {
if ( ! isset( $_GET['page'] ) || 'argus-wpd-firewall' !== $_GET['page'] || 'POST' !== ( $_SERVER['REQUEST_METHOD'] ?? '' ) ) { // phpcs:ignore WordPress.Security.NonceVerification
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have permission to do this.', 'argus-wordpress-defence' ) );
}
if ( isset( $_POST['argus_wpd_unban_nonce'], $_POST['ban_id'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_unban_nonce'] ) ), 'argus_wpd_unban_' . absint( $_POST['ban_id'] ) ) ) { // phpcs:ignore
Argus_Ban_Engine::lift( absint( $_POST['ban_id'] ) );
self::redirect_firewall_tab( 'blocked-ips', __( 'Ban lifted.', 'argus-wordpress-defence' ) );
}
if ( isset( $_POST['argus_wpd_block_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_block_nonce'] ) ), 'argus_wpd_block_ip' ) ) { // phpcs:ignore
$ip = sanitize_text_field( wp_unslash( $_POST['block_ip'] ?? '' ) ); // phpcs:ignore
$reason = sanitize_text_field( wp_unslash( $_POST['block_reason'] ?? '' ) ); // phpcs:ignore
if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
Argus_Ban_Engine::manual_ban( $ip, $reason );
self::redirect_firewall_tab( 'blocked-ips', sprintf( __( 'Blocked %s.', 'argus-wordpress-defence' ), $ip ) );
} else {
self::redirect_firewall_tab( 'manual-block', __( 'That does not look like a valid IP address.', 'argus-wordpress-defence' ) );
}
}
}
public static function ajax_live_feed() {
check_ajax_referer( 'argus_wpd_live_feed', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( null, 403 );
}
$rows = Argus_Console_Stats::latest_blocked_events( 10 );
$out = array();
foreach ( $rows as $row ) {
$out[] = array(
'key' => md5( $row['ip'] . '|' . $row['created_at'] . '|' . $row['type'] ),
'time' => Argus_Console_Stats::live_feed_time_label( $row['created_at'] ),
'desc' => esc_html( $row['desc'] ),
);
}
wp_send_json_success( $out );
}
public static function register_menu() {
add_menu_page(
__( 'ARGUS Defence', 'argus-wordpress-defence' ),
__( 'ARGUS Defence', 'argus-wordpress-defence' ),
'manage_options',
'argus-wpd-dashboard',
array( __CLASS__, 'render_overview' ),
'dashicons-shield',
2
);
add_submenu_page( 'argus-wpd-dashboard', __( 'Overview', 'argus-wordpress-defence' ), __( 'Overview', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-dashboard', array( __CLASS__, 'render_overview' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Firewall', 'argus-wordpress-defence' ), __( 'Firewall', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-firewall', array( __CLASS__, 'render_firewall' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Threats', 'argus-wordpress-defence' ), __( 'Threats', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-threats', array( __CLASS__, 'render_threats' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Findings', 'argus-wordpress-defence' ), __( 'Findings', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-findings', array( __CLASS__, 'render_findings' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Scanner', 'argus-wordpress-defence' ), __( 'Scanner', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-scanner', array( __CLASS__, 'render_scanner' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Quarantine', 'argus-wordpress-defence' ), __( 'Quarantine', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-quarantine', array( __CLASS__, 'render_quarantine' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Cache & Performance', 'argus-wordpress-defence' ), __( 'Cache & Performance', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-cache', array( __CLASS__, 'render_cache' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Backups', 'argus-wordpress-defence' ), __( 'Backups', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-backups', array( __CLASS__, 'render_backups' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Vulnerabilities', 'argus-wordpress-defence' ), __( 'Vulnerabilities', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-vulnerabilities', array( __CLASS__, 'render_vulnerabilities' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Intelligence', 'argus-wordpress-defence' ), __( 'Intelligence', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-intelligence', array( __CLASS__, 'render_intelligence' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'ANIS', 'argus-wordpress-defence' ), __( 'ANIS', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-anis', array( __CLASS__, 'render_anis' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Audit Log', 'argus-wordpress-defence' ), __( 'Audit Log', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-audit-log', array( __CLASS__, 'render_audit_log' ) );
add_submenu_page( 'argus-wpd-dashboard', __( 'Settings', 'argus-wordpress-defence' ), __( 'Settings', 'argus-wordpress-defence' ), 'manage_options', 'argus-wpd-settings', array( __CLASS__, 'render_settings' ) );
}
public static function hide_settings_from_sidebar() {
echo '<style>#adminmenu .wp-submenu a[href$="page=argus-wpd-settings"]{display:none}</style>';
}
public static function enqueue_assets( $hook ) {
if ( false === strpos( $hook, 'argus-wpd' ) ) {
return;
}
$css_path = ARGUS_WPD_DIR . 'assets/css/admin.css';
$version = file_exists( $css_path ) ? filemtime( $css_path ) : ARGUS_WPD_VERSION;
wp_enqueue_style( 'argus-wpd-admin', ARGUS_WPD_URL . 'assets/css/admin.css', array(), $version );
}
public static function render_overview() {
$mu_status = Argus_MU_Installer::status();
$mu_exec_status = Argus_MU_Installer::execution_status();
$mode = Argus_Settings::mode();
$counts = Argus_Findings::open_counts();
$range = isset( $_GET['range'] ) ? sanitize_key( wp_unslash( $_GET['range'] ) ) : '24h'; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $range, array( '24h', '7d', '30d' ), true ) ) {
$range = '24h';
}
$blocked_today = Argus_Console_Stats::blocked_today();
$malicious_ips = Argus_Console_Stats::malicious_ip_count();
$blocked_30d = Argus_Console_Stats::blocked_since_days( 30 );
$security_events = Argus_Console_Stats::security_events_count( 30 );
$series = Argus_Console_Stats::blocked_series( $range );
$malware_open = Argus_Findings::count_open( 'malware' );
$integrity_open = Argus_Findings::count_open( 'integrity' );
$anis_status = Argus_ANIS_Client::status();
include ARGUS_WPD_DIR . 'admin/views/overview.php';
}
public static function render_firewall() {
$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'overview'; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $tab, array( 'overview', 'rule-activity', 'manual-block', 'blocked-ips' ), true ) ) {
$tab = 'overview';
}
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$notice = isset( $_GET['notice'] ) ? sanitize_text_field( wp_unslash( $_GET['notice'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$result = Argus_Ban_Engine::paginated( $page );
$bans = $result['rows'];
$page = $result['page'];
$total_pages = $result['total_pages'];
$rule_hits = Argus_Console_Stats::firewall_rule_hits( 24 );
$rules_active = count( Argus_WAF_Rules::corpus() );
$requests_blocked_24h = Argus_Console_Stats::blocked_today();
$malicious_ips = Argus_Console_Stats::malicious_ip_count();
$attack_categories = Argus_Console_Stats::attack_category_totals( 24 );
$security_actions = Argus_Console_Stats::security_action_totals( 24 );
include ARGUS_WPD_DIR . 'admin/views/firewall.php';
}
protected static function redirect_firewall_tab( $tab, $notice ) {
wp_safe_redirect( add_query_arg( array( 'page' => 'argus-wpd-firewall', 'tab' => $tab, 'notice' => rawurlencode( $notice ) ), admin_url( 'admin.php' ) ) );
exit;
}
public static function render_threats() {
$activity_page = isset( $_GET['activity_paged'] ) ? max( 1, absint( $_GET['activity_paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$activity_result = Argus_Console_Stats::recent_activity_paginated( $activity_page );
$recent_activity = $activity_result['rows'];
$activity_page = $activity_result['page'];
$activity_total_pages = $activity_result['total_pages'];
$category_counts = Argus_Findings::category_counts();
$blocked_per_minute = Argus_Console_Stats::blocked_per_minute_series( 30 );
$latest_blocked = Argus_Console_Stats::latest_blocked_events( 10 );
$live_feed_nonce = wp_create_nonce( 'argus_wpd_live_feed' );
include ARGUS_WPD_DIR . 'admin/views/threats.php';
}
public static function render_findings() {
$view = isset( $_GET['view'] ) ? sanitize_key( wp_unslash( $_GET['view'] ) ) : 'active'; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $view, array( 'active', 'needs_attention', 'resolved', 'accepted' ), true ) ) {
$view = 'active';
}
$finding_id = isset( $_GET['finding'] ) ? absint( $_GET['finding'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$action_result = null;
if ( $finding_id && isset( $_POST['argus_wpd_status_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_status_nonce'] ) ), 'argus_wpd_set_status_' . $finding_id ) ) { // phpcs:ignore
$new_status = sanitize_key( wp_unslash( $_POST['new_status'] ?? '' ) );
if ( in_array( $new_status, array( Argus_Findings::STATUS_ACKNOWLEDGED, Argus_Findings::STATUS_RESOLVED, Argus_Findings::STATUS_RISK_ACCEPTED ), true ) ) {
Argus_Findings::set_status( $finding_id, $new_status );
}
}
if ( $finding_id && isset( $_POST['argus_wpd_action_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_action_nonce'] ) ), 'argus_wpd_run_action_' . $finding_id ) ) { // phpcs:ignore
$finding = Argus_Findings::get( $finding_id );
$action = $finding->evidence['action'] ?? null;
if ( $action && ! empty( $action['type'] ) ) {
$action_result = Argus_Actions::run(
$action['type'],
array( 'plugin' => $action['plugin'] ?? '', 'theme' => $action['theme'] ?? '', 'path' => $action['path'] ?? '' )
);
if ( $action_result['success'] ) {
Argus_Findings::set_status( $finding_id, Argus_Findings::STATUS_RESOLVED );
}
}
}
$findings_notice = '';
if ( $finding_id && isset( $_POST['argus_wpd_delete_finding_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_delete_finding_nonce'] ) ), 'argus_wpd_delete_finding_' . $finding_id ) ) { // phpcs:ignore
Argus_Findings::delete( $finding_id );
$findings_notice = __( 'Finding deleted.', 'argus-wordpress-defence' );
}
if ( isset( $_POST['argus_wpd_resolve_all_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_resolve_all_nonce'] ) ), 'argus_wpd_resolve_all_open' ) ) { // phpcs:ignore
$resolved_count = Argus_Findings::resolve_all_open();
$findings_notice = sprintf(
_n( '%d open finding marked resolved.', '%d open findings marked resolved.', $resolved_count, 'argus-wordpress-defence' ),
$resolved_count
);
}
$result = Argus_Findings::paginated_by_view( $page, $view );
$findings = $result['rows'];
$page = $result['page'];
$total_pages = $result['total_pages'];
$view_counts = Argus_Findings::view_counts();
include ARGUS_WPD_DIR . 'admin/views/findings.php';
}
public static function render_scanner() {
$scan_notice = '';
if ( isset( $_POST['argus_wpd_scan_nonce'], $_POST['scan_type'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_scan_nonce'] ) ), 'argus_wpd_run_scan' ) ) { // phpcs:ignore
$scan_type = sanitize_key( wp_unslash( $_POST['scan_type'] ) );
$started = time();
if ( 'full' === $scan_type ) {
Argus_Integrity::full_scan();
Argus_Malware_Scanner::incremental_scan();
Argus_Scan_History::record( Argus_Scan_History::TYPE_FULL, $started, Argus_Integrity::scan_status()['files_scanned'] );
$scan_notice = __( 'Full scan complete.', 'argus-wordpress-defence' );
} elseif ( 'quick' === $scan_type ) {
Argus_Integrity::incremental_scan();
Argus_Malware_Scanner::incremental_scan();
Argus_Scan_History::record( Argus_Scan_History::TYPE_QUICK, $started );
$scan_notice = __( 'Quick scan complete.', 'argus-wordpress-defence' );
}
}
$scan_status = Argus_Integrity::scan_status();
$malware_open = Argus_Findings::count_open( 'malware' );
$integrity_open = Argus_Findings::count_open( 'integrity' );
$lockdown_status = Argus_Malware_Scanner::lockdown_status();
$quarantine_review_count = Argus_Quarantine::count_open();
$history_page = isset( $_GET['scan_paged'] ) ? max( 1, absint( $_GET['scan_paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$history_result = Argus_Scan_History::paginated( $history_page );
$scan_history = $history_result['rows'];
$history_page = $history_result['page'];
$history_total_pages = $history_result['total_pages'];
include ARGUS_WPD_DIR . 'admin/views/scanner.php';
}
public static function render_quarantine() {
$notice = '';
$notice_type = 'success';
if ( isset( $_POST['quarantine_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$id = absint( $_POST['quarantine_id'] ); // phpcs:ignore WordPress.Security.NonceVerification
if ( isset( $_POST['argus_wpd_quarantine_restore_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_quarantine_restore_nonce'] ) ), 'argus_wpd_quarantine_restore_' . $id ) ) { // phpcs:ignore
$result = Argus_Quarantine::restore( $id );
$notice = $result['message'];
$notice_type = $result['success'] ? 'success' : 'error';
} elseif ( isset( $_POST['argus_wpd_quarantine_delete_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_quarantine_delete_nonce'] ) ), 'argus_wpd_quarantine_delete_' . $id ) ) { // phpcs:ignore
$result = Argus_Quarantine::delete( $id );
$notice = $result['message'];
$notice_type = $result['success'] ? 'success' : 'error';
} elseif ( isset( $_POST['argus_wpd_quarantine_analyse_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_quarantine_analyse_nonce'] ) ), 'argus_wpd_quarantine_analyse_' . $id ) ) { // phpcs:ignore
$result = Argus_Quarantine::analyse( $id );
$notice = $result['success'] ? __( 'Analysis complete.', 'argus-wordpress-defence' ) : $result['message'];
$notice_type = $result['success'] ? 'success' : 'error';
}
}
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$status_filter = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : Argus_Quarantine::STATUS_QUARANTINED; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $status_filter, array( Argus_Quarantine::STATUS_QUARANTINED, Argus_Quarantine::STATUS_RESTORED, Argus_Quarantine::STATUS_DELETED ), true ) ) {
$status_filter = Argus_Quarantine::STATUS_QUARANTINED;
}
$per_page = isset( $_GET['per_page'] ) ? absint( $_GET['per_page'] ) : Argus_Quarantine::PER_PAGE; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $per_page, array( 10, 25, 50 ), true ) ) {
$per_page = Argus_Quarantine::PER_PAGE;
}
$result = Argus_Quarantine::paginated( $page, $status_filter, $per_page );
$items = $result['rows'];
$page = $result['page'];
$total_pages = $result['total_pages'];
$review_count = Argus_Quarantine::count_open();
$legacy_count = Argus_Quarantine::legacy_count();
$status_counts = Argus_Quarantine::counts_by_status();
include ARGUS_WPD_DIR . 'admin/views/quarantine.php';
}
public static function render_cache() {
$notice = '';
$notice_type = 'success';
if ( isset( $_POST['argus_wpd_cache_settings_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_settings_nonce'] ) ), 'argus_wpd_cache_settings' ) ) { // phpcs:ignore
$exclude_raw = sanitize_textarea_field( wp_unslash( $_POST['cache_custom_exclude_paths'] ?? '' ) ); // phpcs:ignore
$exclude_paths = array_values( array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', $exclude_raw ) ) ) );
Argus_Settings::update(
array(
'static_cache_enabled' => ! empty( $_POST['static_cache_enabled'] ), // phpcs:ignore
'static_cache_ttl_secs' => max( 60, absint( $_POST['static_cache_ttl_secs'] ?? 3600 ) ), // phpcs:ignore
'cache_stale_grace_secs' => max( 0, absint( $_POST['cache_stale_grace_secs'] ?? 600 ) ), // phpcs:ignore
'cache_custom_exclude_paths' => $exclude_paths,
)
);
$notice = __( 'Website acceleration settings saved.', 'argus-wordpress-defence' );
}
if ( isset( $_POST['argus_wpd_cache_compression_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_compression_nonce'] ) ), 'argus_wpd_cache_compression' ) ) { // phpcs:ignore
Argus_Settings::update(
array(
'cache_gzip_enabled' => ! empty( $_POST['cache_gzip_enabled'] ), // phpcs:ignore
'cache_gzip_level' => max( 1, min( 9, absint( $_POST['cache_gzip_level'] ?? 6 ) ) ), // phpcs:ignore
'cache_brotli_enabled' => ! empty( $_POST['cache_brotli_enabled'] ), // phpcs:ignore
'cache_brotli_level' => max( 0, min( 11, absint( $_POST['cache_brotli_level'] ?? 5 ) ) ), // phpcs:ignore
'cache_min_compress_bytes' => max( 0, absint( $_POST['cache_min_compress_bytes'] ?? 1024 ) ), // phpcs:ignore
)
);
$notice = __( 'Compression settings saved.', 'argus-wordpress-defence' );
}
if ( isset( $_POST['argus_wpd_cache_warming_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_warming_nonce'] ) ), 'argus_wpd_cache_warming' ) ) { // phpcs:ignore
Argus_Settings::update(
array(
'cache_discovery_enabled' => ! empty( $_POST['cache_discovery_enabled'] ), // phpcs:ignore
'cache_warming_enabled' => ! empty( $_POST['cache_warming_enabled'] ), // phpcs:ignore
'cache_warm_concurrency' => max( 1, min( 10, absint( $_POST['cache_warm_concurrency'] ?? 4 ) ) ), // phpcs:ignore
'cache_warm_batch_size' => max( 1, min( 200, absint( $_POST['cache_warm_batch_size'] ?? 20 ) ) ), // phpcs:ignore
'cache_warm_min_interval_secs' => max( 0, min( 30, absint( $_POST['cache_warm_min_interval_secs'] ?? 1 ) ) ), // phpcs:ignore
)
);
$notice = __( 'Preparation (cache warming) settings saved.', 'argus-wordpress-defence' );
}
if ( isset( $_POST['argus_wpd_cache_purge_all_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_purge_all_nonce'] ) ), 'argus_wpd_cache_purge_all' ) ) { // phpcs:ignore
$count = Argus_Static_Cache::purge_all();
$notice = sprintf( __( 'Cache refreshed -- %d accelerated page(s) cleared.', 'argus-wordpress-defence' ), $count );
}
if ( isset( $_POST['argus_wpd_cache_purge_url_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_purge_url_nonce'] ) ), 'argus_wpd_cache_purge_url' ) ) { // phpcs:ignore
$url = esc_url_raw( wp_unslash( $_POST['purge_url'] ?? '' ) ); // phpcs:ignore
if ( $url ) {
Argus_Static_Cache::purge_url( $url );
$notice = __( 'That page will be re-accelerated on its next visit.', 'argus-wordpress-defence' );
}
}
if ( isset( $_POST['argus_wpd_cache_purge_pattern_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_purge_pattern_nonce'] ) ), 'argus_wpd_cache_purge_pattern' ) ) { // phpcs:ignore
$pattern = sanitize_text_field( wp_unslash( $_POST['purge_pattern'] ?? '' ) ); // phpcs:ignore
if ( $pattern ) {
$count = Argus_Static_Cache::purge_pattern( $pattern );
$notice = sprintf( __( '%d matching page(s) will be re-accelerated on their next visit.', 'argus-wordpress-defence' ), $count );
}
}
if ( isset( $_POST['argus_wpd_cache_run_discovery_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_run_discovery_nonce'] ) ), 'argus_wpd_cache_run_discovery' ) ) { // phpcs:ignore
$result = Argus_Cache_Discovery::run_discovery();
$notice = $result['url_count'] > 0
? sprintf( __( 'Found %d page(s) on your website.', 'argus-wordpress-defence' ), $result['url_count'] )
: __( "ARGUS couldn't find a sitemap for your website yet.", 'argus-wordpress-defence' );
$notice_type = $result['url_count'] > 0 ? 'success' : 'error';
}
if ( isset( $_POST['argus_wpd_cache_run_warming_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_cache_run_warming_nonce'] ) ), 'argus_wpd_cache_run_warming' ) ) { // phpcs:ignore
$result = Argus_Cache_Warmer::process_queue();
$notice = ! empty( $result['skipped'] )
? __( 'ARGUS paused preparation to avoid adding extra load to your website right now -- it will try again automatically.', 'argus-wordpress-defence' )
: sprintf( __( 'Prepared %d page(s).', 'argus-wordpress-defence' ), $result['ok'] ?? 0 );
}
$tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'overview'; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! in_array( $tab, array( 'overview', 'page-cache', 'discovery', 'rules', 'compression', 'warming', 'purge', 'analytics', 'advanced' ), true ) ) {
$tab = 'overview';
}
$settings = Argus_Settings::all();
$cache_stats = Argus_Static_Cache::stats();
$log_summary_30d = Argus_Cache_Log::summary( 30 );
$daily_series = Argus_Cache_Log::daily_series( 14 );
$discovery_summary = class_exists( 'Argus_Cache_Discovery' ) ? Argus_Cache_Discovery::summary() : array();
$warmer_status = class_exists( 'Argus_Cache_Warmer' ) ? Argus_Cache_Warmer::status() : array();
$auto_update = Argus_Auto_Update::status();
$gzip_available = function_exists( 'gzencode' );
$brotli_available = function_exists( 'brotli_compress' );
$compression_stats = Argus_Static_Cache::compression_stats();
$discovered_urls = array();
if ( 'discovery' === $tab && class_exists( 'Argus_Cache_Discovery' ) ) {
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$discovered_urls = Argus_Cache_Discovery::paginated_urls( $page );
}
$recent_log = array();
$log_page = 1;
$log_total_pages = 1;
$cached_urls = array();
if ( 'analytics' === $tab ) {
$log_status_filter = isset( $_GET['status'] ) ? strtoupper( sanitize_key( wp_unslash( $_GET['status'] ) ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification
$log_page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$log_result = Argus_Cache_Log::paginated( $log_page, 10, $log_status_filter );
$recent_log = $log_result['rows'];
$log_page = $log_result['page'];
$log_total_pages = $log_result['total_pages'];
}
if ( 'purge' === $tab ) {
$cached_urls = Argus_Static_Cache::list_cached( 50 );
}
include ARGUS_WPD_DIR . 'admin/views/cache.php';
}
public static function render_backups() {
$notice = '';
$notice_type = 'success';
if ( isset( $_POST['argus_wpd_backup_create_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_backup_create_nonce'] ) ), 'argus_wpd_backup_create' ) ) { // phpcs:ignore
$result = Argus_Backup::create( Argus_Backup::TYPE_MANUAL );
$notice = $result['message'];
$notice_type = $result['success'] ? 'success' : 'error';
}
if ( isset( $_POST['argus_wpd_backup_delete_nonce'], $_POST['backup_id'] ) ) { // phpcs:ignore
$backup_id = absint( $_POST['backup_id'] ); // phpcs:ignore WordPress.Security.NonceVerification
if ( wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_backup_delete_nonce'] ) ), 'argus_wpd_backup_delete_' . $backup_id ) ) {
$result = Argus_Backup::delete( $backup_id );
$notice = $result['message'];
$notice_type = $result['success'] ? 'success' : 'error';
}
}
if ( isset( $_POST['argus_wpd_backup_schedule_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_backup_schedule_nonce'] ) ), 'argus_wpd_backup_schedule' ) ) { // phpcs:ignore
$mode = sanitize_key( wp_unslash( $_POST['backup_schedule_mode'] ?? 'automatic' ) ); // phpcs:ignore
if ( ! in_array( $mode, array( 'automatic', 'manual', 'custom' ), true ) ) {
$mode = 'automatic';
}
Argus_Settings::update( array( 'backup_schedule_mode' => $mode ) );
if ( 'custom' === $mode ) {
$hours = absint( $_POST['backup_interval_hours'] ?? 24 ); // phpcs:ignore
if ( ! in_array( $hours, array( 1, 6, 12, 24, 168 ), true ) ) {
$hours = 24;
}
Argus_Settings::update( array( 'backup_interval_hours' => $hours ) );
} elseif ( 'automatic' === $mode ) {
$active_template = Argus_Templates::active();
$templates = Argus_Templates::all();
if ( $active_template && isset( $templates[ $active_template ]['settings']['backup_interval_hours'] ) ) {
Argus_Settings::update( array( 'backup_interval_hours' => $templates[ $active_template ]['settings']['backup_interval_hours'] ) );
}
}
$notice = __( 'Backup schedule updated.', 'argus-wordpress-defence' );
}
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$result = Argus_Backup::paginated( $page );
$backups = $result['rows'];
$page = $result['page'];
$total_pages = $result['total_pages'];
$backup_status = Argus_Backup::status();
include ARGUS_WPD_DIR . 'admin/views/backups.php';
}
public static function handle_backup_download() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have permission to do this.', 'argus-wordpress-defence' ) );
}
$id = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification
if ( ! $id || ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'argus_wpd_backup_download_' . $id ) ) { // phpcs:ignore
wp_die( esc_html__( 'Invalid or expired download link.', 'argus-wordpress-defence' ) );
}
$backup = Argus_Backup::get( $id );
if ( ! $backup || Argus_Backup::STATUS_COMPLETE !== $backup->status ) {
wp_die( esc_html__( 'Backup not found.', 'argus-wordpress-defence' ) );
}
$path = trailingslashit( Argus_Backup::backup_dir() ) . $backup->filename;
if ( ! file_exists( $path ) ) {
wp_die( esc_html__( 'Backup file not found on disk.', 'argus-wordpress-defence' ) );
}
nocache_headers();
header( 'Content-Type: application/zip' );
header( 'Content-Disposition: attachment; filename="' . $backup->filename . '"' );
header( 'Content-Length: ' . filesize( $path ) );
readfile( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions
exit;
}
public static function render_vulnerabilities() {
$vuln_status = Argus_Vuln_Intel::status();
$severity_counts = array( 'critical' => 0, 'high' => 0, 'medium' => 0, 'low' => 0 );
foreach ( $vuln_status['components'] as $component ) {
if ( Argus_Vuln_Intel::STATUS_VULNERABLE === $component['status'] && isset( $severity_counts[ $component['severity'] ] ) ) {
++$severity_counts[ $component['severity'] ];
}
}
$per_page = 10;
$components_page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$components_total = count( $vuln_status['components'] );
$components_total_pages = max( 1, (int) ceil( $components_total / $per_page ) );
$components_page = min( $components_page, $components_total_pages );
$vuln_status['components'] = array_slice( $vuln_status['components'], ( $components_page - 1 ) * $per_page, $per_page );
include ARGUS_WPD_DIR . 'admin/views/vulnerabilities.php';
}
public static function render_intelligence() {
global $wpdb;
$waf_rule_count = count( Argus_WAF_Rules::corpus() );
$vuln_table = Argus_DB::table( 'vuln_cache' );
$vuln_row_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$vuln_table}" ); // phpcs:ignore
$geoip_status = class_exists( 'Argus_GeoIP_RIR' ) ? Argus_GeoIP_RIR::status() : null;
$anis_status = Argus_ANIS_Client::status();
include ARGUS_WPD_DIR . 'admin/views/intelligence.php';
}
public static function render_anis() {
$anis_status = Argus_ANIS_Client::status();
include ARGUS_WPD_DIR . 'admin/views/anis.php';
}
public static function render_audit_log() {
$page = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification
$search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$severity = isset( $_GET['severity'] ) ? sanitize_key( wp_unslash( $_GET['severity'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$type = isset( $_GET['type'] ) ? sanitize_key( wp_unslash( $_GET['type'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$range = isset( $_GET['range'] ) ? sanitize_key( wp_unslash( $_GET['range'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$range_hours = array( '24h' => 24, '7d' => 24 * 7, '30d' => 24 * 30 );
$filters = array(
'search' => $search,
'severity' => in_array( $severity, array( 'critical', 'high', 'medium', 'low', 'info' ), true ) ? $severity : '',
'type' => $type,
'since' => isset( $range_hours[ $range ] ) ? gmdate( 'Y-m-d H:i:s', time() - $range_hours[ $range ] * HOUR_IN_SECONDS ) : '',
);
$result = Argus_Events::paginated( $page, $filters );
$events = $result['rows'];
$page = $result['page'];
$total_pages = $result['total_pages'];
$event_types = Argus_Events::distinct_types();
include ARGUS_WPD_DIR . 'admin/views/audit-log.php';
}
public static function render_settings() {
$saved = false;
$template_applied = null;
if ( isset( $_POST['argus_wpd_apply_template_nonce'], $_POST['template'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_apply_template_nonce'] ) ), 'argus_wpd_apply_template' ) ) { // phpcs:ignore
$key = sanitize_key( wp_unslash( $_POST['template'] ) ); // phpcs:ignore
if ( class_exists( 'Argus_Templates' ) && Argus_Templates::apply( $key ) ) {
$templates = Argus_Templates::all();
$template_applied = $templates[ $key ]['label'];
}
}
if ( isset( $_POST['argus_wpd_add_exception_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_add_exception_nonce'] ) ), 'argus_wpd_add_exception' ) ) { // phpcs:ignore
$ip = sanitize_text_field( wp_unslash( $_POST['exception_ip'] ?? '' ) ); // phpcs:ignore
if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
Argus_Settings::add_exception( 'ip', $ip, sanitize_text_field( wp_unslash( $_POST['exception_note'] ?? '' ) ) ); // phpcs:ignore
}
}
if ( isset( $_POST['argus_wpd_remove_exception_nonce'], $_POST['exception_value'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_remove_exception_nonce'] ) ), 'argus_wpd_remove_exception' ) ) { // phpcs:ignore
Argus_Settings::remove_exception( 'ip', sanitize_text_field( wp_unslash( $_POST['exception_value'] ) ) ); // phpcs:ignore
}
$update_check_result = null;
if ( isset( $_POST['argus_wpd_check_updates_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_check_updates_nonce'] ) ), 'argus_wpd_check_updates' ) && class_exists( 'Argus_Update_Client' ) ) { // phpcs:ignore
$update_check_result = Argus_Update_Client::check_now();
if ( empty( $update_check_result['message'] ) ) {
$update_check_result['message'] = ! empty( $update_check_result['update_available'] )
? __( 'An update is available.', 'argus-wordpress-defence' )
: __( 'ARGUS Defence is up to date.', 'argus-wordpress-defence' );
}
}
if ( isset( $_POST['argus_wpd_settings_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_settings_nonce'] ) ), 'argus_wpd_save_settings' ) ) { // phpcs:ignore
Argus_Settings::update(
array(
'mode' => sanitize_key( wp_unslash( $_POST['mode'] ?? Argus_Settings::MODE_MONITOR ) ), // phpcs:ignore
'waf_enabled' => ! empty( $_POST['waf_enabled'] ), // phpcs:ignore
'login_protection_enabled' => ! empty( $_POST['login_protection_enabled'] ), // phpcs:ignore
'xmlrpc_block_pingback' => ! empty( $_POST['xmlrpc_block_pingback'] ), // phpcs:ignore
'rest_api_protection_enabled' => ! empty( $_POST['rest_api_protection_enabled'] ), // phpcs:ignore
'integrity_scan_enabled' => ! empty( $_POST['integrity_scan_enabled'] ), // phpcs:ignore
'malware_scan_enabled' => ! empty( $_POST['malware_scan_enabled'] ), // phpcs:ignore
'upload_scan_enabled' => ! empty( $_POST['upload_scan_enabled'] ), // phpcs:ignore
'vuln_intel_enabled' => ! empty( $_POST['vuln_intel_enabled'] ), // phpcs:ignore
'geoip_rir_enabled' => ! empty( $_POST['geoip_rir_enabled'] ), // phpcs:ignore
)
);
$saved = true;
$user = wp_get_current_user();
Argus_Events::record(
'settings_saved',
'info',
sprintf( 'Protection settings updated by %s', $user->user_login ),
array( 'actor' => $user->user_login, 'mode' => Argus_Settings::mode() )
);
}
$settings = Argus_Settings::all();
$geoip_status = class_exists( 'Argus_GeoIP_RIR' ) ? Argus_GeoIP_RIR::status() : null;
$templates = class_exists( 'Argus_Templates' ) ? Argus_Templates::all() : array();
$active_template = class_exists( 'Argus_Templates' ) ? Argus_Templates::active() : '';
$recommended_template = class_exists( 'Argus_Templates' ) ? Argus_Templates::recommended() : null;
include ARGUS_WPD_DIR . 'admin/views/settings.php';
}
}