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.
629 lines
35 KiB
PHP
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';
|
|
}
|
|
}
|