__( 'Status', 'wp-security-pack' ), 'login' => __( 'Login Protection', 'wp-security-pack' ), 'ip' => __( 'IP Control', 'wp-security-pack' ), 'hardening' => __( 'Hardening', 'wp-security-pack' ), 'headers' => __( 'Security Headers', 'wp-security-pack' ), '2fa' => __( '2FA', 'wp-security-pack' ), 'scanner' => __( 'Scanner', 'wp-security-pack' ), 'logs' => __( 'Activity Log', 'wp-security-pack' ), 'tools' => __( 'Tools', 'wp-security-pack' ), ); foreach ( $submenus as $slug => $title ) { add_submenu_page( 'wp-security-pack', $title . ' - ' . __( 'WP Security Pack', 'wp-security-pack' ), $title, 'manage_options', 'status' === $slug ? 'wp-security-pack' : 'wp-security-pack&tab=' . $slug, array( $this, 'render_settings_page' ) ); } } /** * Highlight the correct submenu based on current tab. * * @param string $submenu_file The current submenu file. * @return string */ public function highlight_submenu( $submenu_file ) { global $pagenow; if ( 'admin.php' !== $pagenow ) { return $submenu_file; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; if ( 'wp-security-pack' !== $page ) { return $submenu_file; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended $tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'status'; if ( 'status' === $tab ) { return 'wp-security-pack'; } return 'wp-security-pack&tab=' . $tab; } /** * Add plugin action links (left side - Settings, Deactivate, etc.). * * @param array $links Existing links. * @return array */ public function plugin_action_links( $links ) { $settings_link = sprintf( '%s', admin_url( 'admin.php?page=wp-security-pack' ), __( 'Settings', 'wp-security-pack' ) ); array_unshift( $links, $settings_link ); return $links; } /** * Add plugin row meta links (right side - after version). * * @param array $links Existing meta links. * @param string $file Plugin file. * @return array */ public function plugin_row_meta( $links, $file ) { if ( WPSP_PLUGIN_BASENAME !== $file ) { return $links; } $links[] = sprintf( '%s', 'https://arkhost.com/products-menu.php', __( 'Get Hosting', 'wp-security-pack' ) ); return $links; } /** * Add dashboard widget. */ public function add_dashboard_widget() { if ( ! current_user_can( 'manage_options' ) ) { return; } wp_add_dashboard_widget( 'wpsp_security_widget', __( 'Security Status', 'wp-security-pack' ), array( $this, 'render_dashboard_widget' ) ); } /** * Render dashboard widget. */ public function render_dashboard_widget() { $checks = $this->get_security_checks(); $enabled_count = 0; $total_count = count( $checks ); foreach ( $checks as $check ) { if ( $check['status'] ) { $enabled_count++; } } $score = $total_count > 0 ? round( ( $enabled_count / $total_count ) * 100 ) : 0; // Get recent activity stats. $stats = WPSP_Activity_Log::get_stats( 7 ); ?>
%
__( 'Status', 'wp-security-pack' ), 'login' => __( 'Login Protection', 'wp-security-pack' ), 'ip' => __( 'IP Control', 'wp-security-pack' ), 'hardening' => __( 'Hardening', 'wp-security-pack' ), 'headers' => __( 'Security Headers', 'wp-security-pack' ), '2fa' => __( '2FA', 'wp-security-pack' ), 'scanner' => __( 'Scanner', 'wp-security-pack' ), 'logs' => __( 'Activity Log', 'wp-security-pack' ), 'tools' => __( 'Tools', 'wp-security-pack' ), ); ?>

render_status_tab(); break; case 'login': $this->render_login_tab(); break; case 'ip': $this->render_ip_tab(); break; case 'hardening': $this->render_hardening_tab(); break; case 'headers': $this->render_headers_tab(); break; case '2fa': $this->render_2fa_tab(); break; case 'scanner': $this->render_scanner_tab(); break; case 'logs': $this->render_logs_tab(); break; case 'tools': $this->render_tools_tab(); break; } if ( ! in_array( $current_tab, array( 'status', 'logs', 'tools' ), true ) ) { submit_button(); } ?>
get_security_checks(); $enabled_count = 0; $total_count = count( $checks ); foreach ( $checks as $check ) { if ( $check['status'] ) { $enabled_count++; } } $score = $total_count > 0 ? round( ( $enabled_count / $total_count ) * 100 ) : 0; ?>

%
$check ) : ?>

prefix ) : ?> wp_ prefix ); ?>

readme.html
license.txt
__( 'Login Attempt Limiting', 'wp-security-pack' ), 'description' => __( 'Limits failed login attempts to prevent brute force attacks', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'login_limit_enabled', true ), 'tab' => 'login', ); $checks['honeypot'] = array( 'name' => __( 'Login Honeypot', 'wp-security-pack' ), 'description' => __( 'Hidden field that traps automated bots', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'honeypot_enabled', true ), 'tab' => 'login', ); $checks['hide_login_errors'] = array( 'name' => __( 'Login Errors Hidden', 'wp-security-pack' ), 'description' => __( 'Generic error message prevents username enumeration', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'hide_login_errors', true ), 'tab' => 'login', ); // Hardening. $checks['xmlrpc'] = array( 'name' => __( 'XML-RPC Disabled', 'wp-security-pack' ), 'description' => __( 'Blocks XML-RPC endpoint commonly used in attacks', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'disable_xmlrpc', true ), 'tab' => 'hardening', ); $checks['file_editing'] = array( 'name' => __( 'File Editor Disabled', 'wp-security-pack' ), 'description' => __( 'Prevents editing theme/plugin files from dashboard', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'disable_file_editing', true ), 'tab' => 'hardening', ); $checks['rest_api'] = array( 'name' => __( 'REST API Restricted', 'wp-security-pack' ), 'description' => __( 'Requires authentication for REST API access', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'restrict_rest_api', true ), 'tab' => 'hardening', ); $checks['user_enum'] = array( 'name' => __( 'User Enumeration Blocked', 'wp-security-pack' ), 'description' => __( 'Prevents attackers from discovering usernames', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'disable_user_enumeration', true ), 'tab' => 'hardening', ); $checks['pingbacks'] = array( 'name' => __( 'Pingbacks Disabled', 'wp-security-pack' ), 'description' => __( 'Prevents pingback-based DDoS amplification', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'disable_pingbacks', true ), 'tab' => 'hardening', ); $checks['wp_version'] = array( 'name' => __( 'WP Version Hidden', 'wp-security-pack' ), 'description' => __( 'Hides WordPress version from public view', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'remove_wp_version', true ), 'tab' => 'hardening', ); $checks['security_headers'] = array( 'name' => __( 'Security Headers', 'wp-security-pack' ), 'description' => __( 'HTTP headers that enable browser security features', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'add_security_headers', true ), 'tab' => 'headers', ); // 2FA - only green if enforced for admins (just "enabled" means users CAN set it up, not that they have). $two_fa_enabled = WP_Security_Pack::get_setting( 'two_factor_enabled', false ); $two_fa_enforced = WP_Security_Pack::get_setting( 'two_factor_enforce_admin', false ); $checks['two_factor'] = array( 'name' => __( 'Two-Factor Authentication', 'wp-security-pack' ), 'description' => $two_fa_enabled && ! $two_fa_enforced ? __( 'Available but not enforced for admins', 'wp-security-pack' ) : __( 'Enforced for administrator accounts', 'wp-security-pack' ), 'status' => $two_fa_enabled && $two_fa_enforced, 'tab' => '2fa', ); // Monitoring. $checks['file_integrity'] = array( 'name' => __( 'File Integrity Monitoring', 'wp-security-pack' ), 'description' => __( 'Detects unauthorized changes to WordPress core', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'file_integrity_enabled', true ), 'tab' => 'scanner', ); $checks['malware_scan'] = array( 'name' => __( 'Malware Scanning', 'wp-security-pack' ), 'description' => __( 'Scans files for malicious code patterns', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'malware_scan_enabled', true ), 'tab' => 'scanner', ); // Optional features (not counted negatively if disabled). $checks['custom_login'] = array( 'name' => __( 'Custom Login URL', 'wp-security-pack' ), 'description' => __( 'Hides wp-login.php from automated scanners', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'login_rename_enabled', false ), 'tab' => 'login', ); $checks['geo_blocking'] = array( 'name' => __( 'Country Blocking', 'wp-security-pack' ), 'description' => __( 'Blocks access from specific countries', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'geo_blocking_enabled', false ), 'tab' => 'ip', ); $checks['auto_blacklist'] = array( 'name' => __( 'Auto-Blacklist Repeat Offenders', 'wp-security-pack' ), 'description' => __( 'Permanently blocks IPs with repeated lockouts', 'wp-security-pack' ), 'status' => WP_Security_Pack::get_setting( 'auto_blacklist_enabled', false ), 'tab' => 'ip', ); // Environment checks (no tab - these are recommendations). global $wpdb; $checks['ssl'] = array( 'name' => __( 'SSL/HTTPS', 'wp-security-pack' ), 'description' => is_ssl() ? __( 'Site is served over HTTPS', 'wp-security-pack' ) : __( 'Site should use HTTPS for security', 'wp-security-pack' ), 'status' => is_ssl(), 'tab' => '', ); $checks['debug_mode'] = array( 'name' => __( 'Debug Mode Disabled', 'wp-security-pack' ), 'description' => defined( 'WP_DEBUG' ) && WP_DEBUG ? __( 'WP_DEBUG is enabled - disable in production', 'wp-security-pack' ) : __( 'Debug mode is properly disabled', 'wp-security-pack' ), 'status' => ! ( defined( 'WP_DEBUG' ) && WP_DEBUG ), 'tab' => '', ); $checks['db_prefix'] = array( 'name' => __( 'Database Prefix Changed', 'wp-security-pack' ), 'description' => 'wp_' === $wpdb->prefix ? __( 'Using default wp_ prefix - consider changing', 'wp-security-pack' ) : __( 'Using custom database prefix', 'wp-security-pack' ), 'status' => 'wp_' !== $wpdb->prefix, 'tab' => '', ); $admin_user = get_user_by( 'login', 'admin' ); $checks['admin_username'] = array( 'name' => __( 'No "admin" Username', 'wp-security-pack' ), 'description' => $admin_user ? __( 'Default "admin" username exists - consider renaming', 'wp-security-pack' ) : __( 'No user with "admin" username', 'wp-security-pack' ), 'status' => ! $admin_user, 'tab' => '', ); $checks['php_version'] = array( 'name' => __( 'PHP Version', 'wp-security-pack' ), 'description' => version_compare( PHP_VERSION, '8.0', '<' ) ? sprintf( /* translators: %s: PHP version */ __( 'PHP %s is outdated - update recommended', 'wp-security-pack' ), PHP_VERSION ) : sprintf( /* translators: %s: PHP version */ __( 'Running PHP %s', 'wp-security-pack' ), PHP_VERSION ), 'status' => version_compare( PHP_VERSION, '8.0', '>=' ), 'tab' => '', ); // Check if auto-updates are enabled for core. $auto_updates_enabled = defined( 'WP_AUTO_UPDATE_CORE' ) && WP_AUTO_UPDATE_CORE; // Also check the database option. if ( ! $auto_updates_enabled ) { $auto_updates_enabled = 'true' === get_site_option( 'auto_update_core_major' ) || 'true' === get_site_option( 'auto_update_core_minor' ); } $checks['auto_updates'] = array( 'name' => __( 'Auto-Updates Enabled', 'wp-security-pack' ), 'description' => $auto_updates_enabled ? __( 'WordPress core auto-updates are enabled', 'wp-security-pack' ) : __( 'Enable auto-updates for security patches', 'wp-security-pack' ), 'status' => $auto_updates_enabled, 'tab' => '', ); return $checks; } /** * Render login protection tab. */ private function render_login_tab() { ?>


get_component( 'geo_blocking' ); $db_exists = $geo_blocking && $geo_blocking->database_exists(); if ( ! $db_exists ) : ?>


' . esc_html__( 'IP Control', 'wp-security-pack' ) . '' ); ?>



' . esc_html( WPSP_Helper::get_client_ip() ) . '' ); ?>

get_component( 'ip_control' ); if ( $ip_control ) { $blocked_ips = $ip_control->get_blocked_ips(); } $geo_blocking = wpsp()->get_component( 'geo_blocking' ); $db_info = $geo_blocking ? $geo_blocking->get_database_info() : array( 'exists' => false ); $countries = WPSP_Helper::get_countries_with_flags(); ?>

- -


' . esc_html( WPSP_Helper::get_client_ip() ) . '' ); ?>

ip_address ); ?> failed_attempts ); ?> lockout_until ); ?>

Theme Editor and Plugins > Plugin Editor. If an attacker gains admin access, they cannot inject malicious code directly.', 'wp-security-pack' ); ?>

get_default_headers(); $headers = WP_Security_Pack::get_setting( 'security_headers', $default_headers ); ?>

securityheaders.com' ); ?>



'_wpsp_2fa_enabled', 'meta_value' => '1', 'fields' => 'ID', ) ); $total_admins = count( get_users( array( 'role' => 'administrator', 'fields' => 'ID', ) ) ); $admins_with_2fa = 0; foreach ( $users_with_2fa as $user_id ) { if ( user_can( $user_id, 'manage_options' ) ) { $admins_with_2fa++; } } ?>

0 || $total_admins > 0 ) : ?>

  1. ' . esc_html__( 'Profile page', 'wp-security-pack' ) . '' ); ?>

get_last_scan_results(); $malware_scanner = new WPSP_Malware_Scanner(); $malware_results = $malware_scanner->get_last_scan_results(); $file_changes_count = count( $file_results['changes']['modified'] ?? array() ); $malware_issues_count = count( $malware_results['results'] ?? array() ); ?> 0 || $malware_results['time'] > 0 ) : ?>
0 ? esc_html( $file_changes_count ) : '✓'; ?>
0 ? esc_html( $malware_issues_count ) : '✓'; ?>

0 ) : ?> 0 ) : ?>

0 ) : ?>

0 ) : ?>

$findings ) : ?>

0 ) : ?>

get_quarantined_files(); if ( ! empty( $quarantined_files ) ) : ?>

$meta ) : ?>

$per_page, 'offset' => $offset, 'event_type' => $filter_type, ) ); $total = WPSP_Activity_Log::get_log_count( array( 'event_type' => $filter_type ) ); $pages = ceil( $total / $per_page ); $stats = WPSP_Activity_Log::get_stats( 30 ); ?>

created_at ); ?> event_type ) ); ?> country_code ) : ?> country_code ) ); ?> - ip_address ); ?> username ? $log->username : '-' ); ?> details ? $log->details : '-' ); ?>
1 ) : ?>
add_query_arg( 'paged', '%#%' ), 'format' => '', 'current' => $page, 'total' => $pages, ) ) ); ?>

get_component( 'geo_blocking' ); $geo_info = $geo_blocking ? $geo_blocking->get_database_info() : array( 'exists' => false ); $country_code = $geo_blocking && $current_ip ? $geo_blocking->get_country_code( $current_ip ) : null; ?>

get_component( 'ip_control' ); $is_whitelisted = $ip_control && $ip_control->is_whitelisted( $current_ip ); ?>


wp-content/plugins/wp-security-pack


TRUNCATE TABLE prefix ); ?>wpsp_lockouts;

()
() ()

__( 'Permission denied.', 'wp-security-pack' ) ) ); } WPSP_Activity_Log::clear_all_logs(); wp_send_json_success(); } /** * AJAX: Whitelist IP. * * Adds an IP to the whitelist setting. */ public function ajax_whitelist_ip() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $ip = isset( $_POST['ip'] ) ? sanitize_text_field( wp_unslash( $_POST['ip'] ) ) : ''; if ( empty( $ip ) || ! filter_var( $ip, FILTER_VALIDATE_IP ) ) { wp_send_json_error( array( 'message' => __( 'Invalid IP address.', 'wp-security-pack' ) ) ); } // Get current whitelist. $whitelist = WP_Security_Pack::get_setting( 'ip_whitelist', '' ); // Check if IP is already in whitelist. $whitelist_array = array_filter( array_map( 'trim', explode( "\n", $whitelist ) ) ); if ( in_array( $ip, $whitelist_array, true ) ) { wp_send_json_error( array( 'message' => __( 'IP is already whitelisted.', 'wp-security-pack' ) ) ); } // Add IP to whitelist. $whitelist_array[] = $ip; $new_whitelist = implode( "\n", $whitelist_array ); WP_Security_Pack::update_setting( 'ip_whitelist', $new_whitelist ); // Also remove from lockouts if present. $ip_control = wpsp()->get_component( 'ip_control' ); if ( $ip_control ) { $ip_control->unblock_ip( $ip ); } wp_send_json_success(); } /** * AJAX: Run file scan. */ public function ajax_run_file_scan() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $file_integrity = new WPSP_File_Integrity(); $results = $file_integrity->scan_core_files( true ); wp_send_json_success( $results ); } /** * AJAX: Run malware scan. */ public function ajax_run_malware_scan() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } // Increase time limit. set_time_limit( 300 ); $scanner = new WPSP_Malware_Scanner(); $results = $scanner->scan_files(); update_option( WPSP_Malware_Scanner::RESULTS_OPTION, $results ); update_option( WPSP_Malware_Scanner::LAST_SCAN_OPTION, time() ); wp_send_json_success( $results ); } /** * AJAX: Reset file integrity baseline. */ public function ajax_reset_file_baseline() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $file_integrity = new WPSP_File_Integrity(); $file_integrity->reset_baseline(); // Run a fresh scan to establish new baseline. $file_integrity->scan_core_files( true ); wp_send_json_success(); } /** * AJAX: Clear malware scan results. */ public function ajax_clear_malware_results() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $scanner = new WPSP_Malware_Scanner(); $scanner->clear_results(); wp_send_json_success(); } /** * AJAX: Download GeoIP database. */ public function ajax_download_geo_db() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $geo_blocking = wpsp()->get_component( 'geo_blocking' ); if ( ! $geo_blocking ) { wp_send_json_error( array( 'message' => __( 'Geo blocking not available.', 'wp-security-pack' ) ) ); } $result = $geo_blocking->download_database(); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success(); } /** * AJAX: Send test email. */ public function ajax_test_email() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; if ( empty( $email ) ) { $email = get_option( 'admin_email' ); } if ( ! is_email( $email ) ) { wp_send_json_error( array( 'message' => __( 'Invalid email address.', 'wp-security-pack' ) ) ); } $site_name = get_bloginfo( 'name' ); $subject = sprintf( /* translators: %s: Site name */ __( '[%s] WP Security Pack - Test Email', 'wp-security-pack' ), $site_name ); $message = sprintf( /* translators: 1: Site name, 2: Site URL */ __( "This is a test email from WP Security Pack.\n\nIf you received this email, your email alerts are configured correctly.\n\nSite: %1\$s\nURL: %2\$s", 'wp-security-pack' ), $site_name, home_url() ); $sent = wp_mail( $email, $subject, $message ); if ( $sent ) { wp_send_json_success(); } else { wp_send_json_error( array( 'message' => __( 'Failed to send email. Check your server mail configuration.', 'wp-security-pack' ) ) ); } } /** * AJAX: Force logout all users. */ public function ajax_force_logout_all() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } // Get all users and destroy their sessions. $users = get_users( array( 'fields' => 'ID' ) ); foreach ( $users as $user_id ) { $sessions = WP_Session_Tokens::get_instance( $user_id ); $sessions->destroy_all(); } // Log the action. WPSP_Activity_Log::log( 'force_logout', WPSP_Helper::get_client_ip(), wp_get_current_user()->user_login, __( 'All user sessions terminated', 'wp-security-pack' ) ); wp_send_json_success(); } /** * AJAX: Export settings. */ public function ajax_export_settings() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $settings = get_option( 'wpsp_settings', array() ); wp_send_json_success( $settings ); } /** * AJAX: Import settings. */ public function ajax_import_settings() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $settings_json = isset( $_POST['settings'] ) ? wp_unslash( $_POST['settings'] ) : ''; if ( empty( $settings_json ) ) { wp_send_json_error( array( 'message' => __( 'No settings data provided.', 'wp-security-pack' ) ) ); } $settings = json_decode( $settings_json, true ); if ( null === $settings ) { wp_send_json_error( array( 'message' => __( 'Invalid JSON format.', 'wp-security-pack' ) ) ); } // Sanitize the imported settings. $sanitized = $this->sanitize_settings( $settings ); update_option( 'wpsp_settings', $sanitized ); wp_send_json_success(); } /** * AJAX: Export logs as CSV. */ public function ajax_export_logs() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $logs = WPSP_Activity_Log::get_logs( array( 'limit' => 10000 ) ); $csv_lines = array(); $csv_lines[] = 'Time,Event,IP Address,Country,Username,Details,User Agent'; foreach ( $logs as $log ) { $csv_lines[] = sprintf( '"%s","%s","%s","%s","%s","%s","%s"', str_replace( '"', '""', $log->created_at ), str_replace( '"', '""', WPSP_Activity_Log::get_event_label( $log->event_type ) ), str_replace( '"', '""', $log->ip_address ), str_replace( '"', '""', $log->country_code ? $log->country_code : '' ), str_replace( '"', '""', $log->username ? $log->username : '' ), str_replace( '"', '""', $log->details ? $log->details : '' ), str_replace( '"', '""', $log->user_agent ? $log->user_agent : '' ) ); } wp_send_json_success( array( 'csv' => implode( "\n", $csv_lines ) ) ); } /** * AJAX: Clear all lockouts. */ public function ajax_clear_lockouts() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } global $wpdb; $table = WPSP_DB::get_lockout_table(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared $wpdb->query( "TRUNCATE TABLE {$table}" ); wp_send_json_success(); } /** * AJAX: Reset all settings to defaults. */ public function ajax_reset_settings() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $defaults = WP_Security_Pack::get_default_settings(); update_option( 'wpsp_settings', $defaults ); wp_send_json_success(); } /** * AJAX: Quarantine a suspicious file. */ public function ajax_quarantine_file() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $file_path = isset( $_POST['file_path'] ) ? sanitize_text_field( wp_unslash( $_POST['file_path'] ) ) : ''; if ( empty( $file_path ) ) { wp_send_json_error( array( 'message' => __( 'No file specified.', 'wp-security-pack' ) ) ); } $scanner = new WPSP_Malware_Scanner(); $result = $scanner->quarantine_file( $file_path ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( $result ); } /** * AJAX: Restore a file from quarantine. */ public function ajax_restore_file() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $quarantine_name = isset( $_POST['quarantine_name'] ) ? sanitize_file_name( wp_unslash( $_POST['quarantine_name'] ) ) : ''; if ( empty( $quarantine_name ) ) { wp_send_json_error( array( 'message' => __( 'No file specified.', 'wp-security-pack' ) ) ); } $scanner = new WPSP_Malware_Scanner(); $result = $scanner->restore_file( $quarantine_name ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( $result ); } /** * AJAX: Delete a quarantined file permanently. */ public function ajax_delete_quarantined() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $quarantine_name = isset( $_POST['quarantine_name'] ) ? sanitize_file_name( wp_unslash( $_POST['quarantine_name'] ) ) : ''; if ( empty( $quarantine_name ) ) { wp_send_json_error( array( 'message' => __( 'No file specified.', 'wp-security-pack' ) ) ); } $scanner = new WPSP_Malware_Scanner(); $result = $scanner->delete_quarantined_file( $quarantine_name ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( $result ); } /** * AJAX: Delete WordPress info files (readme.html, license.txt). */ public function ajax_delete_wp_file() { check_ajax_referer( 'wpsp_admin' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'wp-security-pack' ) ) ); } $file = isset( $_POST['file'] ) ? sanitize_file_name( wp_unslash( $_POST['file'] ) ) : ''; // Only allow specific safe files to be deleted. $allowed_files = array( 'readme.html', 'license.txt' ); if ( ! in_array( $file, $allowed_files, true ) ) { wp_send_json_error( array( 'message' => __( 'Invalid file.', 'wp-security-pack' ) ) ); } $file_path = ABSPATH . $file; if ( ! file_exists( $file_path ) ) { wp_send_json_error( array( 'message' => __( 'File not found.', 'wp-security-pack' ) ) ); } // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink if ( ! unlink( $file_path ) ) { wp_send_json_error( array( 'message' => __( 'Failed to delete file. Check file permissions.', 'wp-security-pack' ) ) ); } wp_send_json_success(); } }