plugin = $plugin_instance; } public function ajax_get_dashboard_stats() { check_ajax_referer('wp_ajax_advaipbl_get_dashboard_stats', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => 'Permission denied.']); } $stats = $this->plugin->dashboard_manager->get_dashboard_stats(); if ($stats) { wp_send_json_success($stats); } else { wp_send_json_error(['message' => 'Could not retrieve stats.']); } } /** * AJAX callback for the IP Inspector. */ public function ajax_inspect_ip() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(__('Permission denied.', 'advanced-ip-blocker')); } check_ajax_referer('advaipbl_inspect_ip_nonce', 'nonce'); $query = isset($_POST['query']) ? sanitize_text_field(wp_unslash($_POST['query'])) : ''; if (!$query) { wp_send_json_error(__('Please enter an IP address or ASN.', 'advanced-ip-blocker')); } $ip = ''; $asn = ''; if (preg_match('/^AS\d+$/i', $query)) { $asn = strtoupper($query); } elseif (filter_var($query, FILTER_VALIDATE_IP)) { $ip = $query; } else { wp_send_json_error(__('Invalid IP address or ASN format.', 'advanced-ip-blocker')); } $data = [ 'geo' => [ 'country' => null, 'city' => null, 'asn' => null, 'isp' => null, 'hostname' => null, 'lat' => null, 'lon' => null, 'provider' => $this->plugin->options['geolocation_method'] === 'local_db' ? 'Local MaxMind Database' : 'External API' ], 'status' => [ 'is_whitelisted' => false, 'is_blocked' => false, 'is_bot' => false ], 'metrics' => [ 'abuse_score' => null, 'abuse_threshold' => 90, 'has_vip_pass' => false, 'aib_network' => false, 'spamhaus' => false ] ]; if ($ip) { $loc = $this->plugin->geolocation_manager->fetch_location($ip); if ($loc && empty($loc['error'])) { $data['geo']['country'] = isset($loc['country']) ? $loc['country'] : (isset($loc['country_code']) ? $loc['country_code'] : null); $data['geo']['city'] = isset($loc['city']) ? $loc['city'] : null; $data['geo']['asn'] = isset($loc['as']) ? $loc['as'] : (isset($loc['isp']) ? $loc['isp'] : null); $data['geo']['isp'] = isset($loc['isp']) ? $loc['isp'] : null; $data['geo']['lat'] = isset($loc['lat']) ? $loc['lat'] : null; $data['geo']['lon'] = isset($loc['lon']) ? $loc['lon'] : null; } $hostname = gethostbyaddr($ip); if ($hostname !== $ip && $hostname !== false) { $data['geo']['hostname'] = $hostname; } $data['status']['is_whitelisted'] = $this->plugin->is_whitelisted($ip); $data['status']['is_bot'] = $this->plugin->bot_verifier->is_verified_bot($ip, ''); $data['status']['is_blocked'] = $this->plugin->is_ip_actively_blocked($ip); if (!empty($this->plugin->options['enable_js_challenge'])) { $data['metrics']['has_vip_pass'] = $this->plugin->js_challenge_manager->is_vip_pass_valid($ip); } $data['metrics']['abuse_threshold'] = (int) ($this->plugin->options['abuseipdb_threshold'] ?? 90); if (!empty($this->plugin->options['enable_abuseipdb'])) { $abuse_data = $this->plugin->abuseipdb_manager->check_ip($ip); if (isset($abuse_data['score'])) { $data['metrics']['abuse_score'] = $abuse_data['score']; } } $data['metrics']['aib_network'] = false; $data['metrics']['aib_score'] = 0; if (isset($this->plugin->community_manager)) { if ($this->plugin->community_manager->is_ip_blocked($ip)) { $data['metrics']['aib_network'] = true; } $api_token = $this->plugin->options['api_token_v3'] ?? ''; if (!empty($api_token)) { $response = wp_remote_get('https://advaipbl.com/wp-json/aib-api/v3/scanner/check-ip?ip=' . urlencode($ip) . '&v=' . ADVAIPBL_VERSION, [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_token, 'X-AIB-Auth' => 'Bearer ' . $api_token, 'Accept' => 'application/json' ], 'timeout' => 5 ]); if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) { $body = json_decode(wp_remote_retrieve_body($response), true); if (isset($body['report_count'])) { $data['metrics']['aib_score'] = (int)$body['report_count']; } } } } $data['metrics']['spamhaus'] = false; if ($data['geo']['asn']) { if (preg_match('/\d+/', $data['geo']['asn'], $matches)) { $asn_number = intval($matches[0]); $spamhaus_list = get_option('advaipbl_spamhaus_asn_list', []); if (in_array($asn_number, $spamhaus_list, true)) { $data['metrics']['spamhaus'] = true; } } } } elseif ($asn) { $data['geo']['asn'] = $asn; $data['geo']['provider'] = 'ASN Lookup'; $data['status']['is_blocked'] = false; $data['status']['is_whitelisted'] = false; if (preg_match('/\d+/', $asn, $matches)) { $asn_number = intval($matches[0]); $response = wp_remote_get('https://stat.ripe.net/data/as-overview/data.json?resource=' . $asn_number, ['timeout' => 5]); if (!is_wp_error($response)) { $body = wp_remote_retrieve_body($response); $json = json_decode($body, true); if (isset($json['status']) && $json['status'] === 'ok' && !empty($json['data']['holder'])) { $data['geo']['isp'] = $json['data']['holder']; $data['geo']['provider'] = 'RIPE Stat API (ASN Lookup)'; } } } $whitelisted_asns_raw = get_option('advaipbl_whitelisted_asns', []); $clean_whitelist = []; if (!empty($whitelisted_asns_raw)) { foreach ($whitelisted_asns_raw as $entry) { $parts = explode('#', $entry); $clean_val = strtoupper(trim($parts[0])); if (!empty($clean_val)) { $clean_whitelist[] = $clean_val; } } } if (in_array(strtoupper($asn), $clean_whitelist, true)) { $data['status']['is_whitelisted'] = true; } $blocked_asns_raw = get_option('advaipbl_blocked_asns', []); $clean_blocklist = []; if (!empty($blocked_asns_raw)) { foreach ($blocked_asns_raw as $entry) { $parts = explode('#', $entry); $clean_val = strtoupper(trim($parts[0])); if (!empty($clean_val)) { $clean_blocklist[] = $clean_val; } } } if (in_array(strtoupper($asn), $clean_blocklist, true)) { $data['status']['is_blocked'] = true; } if (preg_match('/\d+/', $asn, $matches)) { $asn_number = intval($matches[0]); $spamhaus_list = get_option('advaipbl_spamhaus_asn_list', []); if (in_array($asn_number, $spamhaus_list, true)) { $data['status']['is_blocked'] = true; $data['metrics']['spamhaus'] = true; } } } wp_send_json_success($data); } /** * AJAX callback to reset an IP threat score. */ public function ajax_reset_threat_score() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_reset_score_nonce', 'nonce'); $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : ''; if (!$ip) { wp_send_json_error(['message' => __('Invalid IP address.', 'advanced-ip-blocker')]); } $success = $this->plugin->threat_score_manager->reset_score($ip); $this->plugin->desbloquear_ip($ip); if ($success) { $this->plugin->purge_all_page_caches(); /* translators: %s is a placeholder */ $this->plugin->log_event(sprintf(__('Threat score for IP %1$s was manually reset by %2$s.', 'advanced-ip-blocker'), $ip, $this->plugin->get_current_admin_username()), 'info'); wp_send_json_success(['message' => __('Score reset and IP unblocked successfully.', 'advanced-ip-blocker')]); } else { wp_send_json_error(['message' => __('Failed to reset score.', 'advanced-ip-blocker')]); } } /** * AJAX callback to whitelist a signature and remove it from the blocklist. */ public function ajax_whitelist_signature() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_whitelist_signature_nonce', 'nonce'); $hash = isset($_POST['hash']) ? sanitize_text_field(wp_unslash($_POST['hash'])) : ''; if (strlen($hash) !== 64) { wp_send_json_error(['message' => __('Invalid signature hash.', 'advanced-ip-blocker')]); } $details = $this->plugin->fingerprint_manager->get_signature_details($hash); if ($details === false) { wp_send_json_error(['message' => __('Could not retrieve signature details to create whitelist entry.', 'advanced-ip-blocker')]); } $entry_lines = ["\n# Signature Components:"]; $entry_lines[] = "# User-Agent: " . ($details['sample_user_agent'] ?? 'N/A'); if (!empty($details['sample_headers'])) { foreach ($details['sample_headers'] as $key => $value) { $entry_lines[] = "# " . $key . ": " . $value; } } $entry_lines[] = $hash; $entry_to_add = implode("\n", $entry_lines); $options = get_option(ADVAIPBL_Main::OPTION_SETTINGS, []); $current_whitelist = $options['trusted_signature_hashes'] ?? ''; $new_whitelist = $current_whitelist . "\n" . $entry_to_add; $options['trusted_signature_hashes'] = trim($new_whitelist); update_option(ADVAIPBL_Main::OPTION_SETTINGS, $options); $this->plugin->fingerprint_manager->delete_signature($hash); /* translators: %s is a placeholder */ $this->plugin->log_event(sprintf(__('Signature %1$s... whitelisted by %2$s.', 'advanced-ip-blocker'), substr($hash, 0, 12), $this->plugin->get_current_admin_username()), 'info'); wp_send_json_success(['message' => __('Signature whitelisted successfully.', 'advanced-ip-blocker')]); } /** * AJAX callback to delete a malicious signature. */ public function ajax_delete_signature() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_delete_signature_nonce', 'nonce'); $signature_hash = isset($_POST['hash']) ? sanitize_text_field(wp_unslash($_POST['hash'])) : ''; if (strlen($signature_hash) !== 64) { wp_send_json_error(['message' => __('Invalid signature hash format.', 'advanced-ip-blocker')]); } $success = $this->plugin->fingerprint_manager->delete_signature($signature_hash); if ($success) { /* translators: %s is a placeholder */ $this->plugin->log_event(sprintf(__('Malicious signature %1$s... was manually deleted by %2$s.', 'advanced-ip-blocker'), substr($signature_hash, 0, 12), $this->plugin->get_current_admin_username()), 'warning'); wp_send_json_success(['message' => __('Signature deleted successfully.', 'advanced-ip-blocker')]); } else { wp_send_json_error(['message' => __('Failed to delete signature. It might have already expired or been removed.', 'advanced-ip-blocker')]); } } /** * AJAX callback to get details of a malicious signature. */ public function ajax_get_signature_details() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_get_signature_details_nonce', 'nonce'); $signature_hash = isset($_POST['hash']) ? sanitize_text_field(wp_unslash($_POST['hash'])) : ''; if (strlen($signature_hash) !== 64) { wp_send_json_error(['message' => __('Invalid signature hash format.', 'advanced-ip-blocker')]); } $details = $this->plugin->fingerprint_manager->get_signature_details($signature_hash); if ($details !== false) { wp_send_json_success(['details' => $details]); } else { wp_send_json_error(['message' => __('Could not retrieve signature details.', 'advanced-ip-blocker')]); } } /** * AJAX callback to get Endpoint Lockdown details. */ public function ajax_get_lockdown_details() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_get_lockdown_details_nonce', 'nonce'); $lockdown_id = isset($_POST['id']) ? absint($_POST['id']) : 0; if (!$lockdown_id) { wp_send_json_error(['message' => __('Invalid Lockdown ID.', 'advanced-ip-blocker')]); } global $wpdb; $table_name = $wpdb->prefix . 'advaipbl_endpoint_lockdowns'; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter $lockdown = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d", $lockdown_id), ARRAY_A); if ($lockdown) { wp_send_json_success(['details' => $lockdown]); } else { wp_send_json_error(['message' => __('Could not retrieve lockdown details.', 'advanced-ip-blocker')]); } } /** * AJAX callback to get the event history of an IP. */ public function ajax_get_score_history() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_get_history_nonce', 'nonce'); $ip = isset($_POST['ip']) ? sanitize_text_field(wp_unslash($_POST['ip'])) : ''; if (!$ip) { wp_send_json_error(['message' => __('Invalid IP address.', 'advanced-ip-blocker')]); } $history = $this->plugin->threat_score_manager->get_log_details($ip); if ($history !== false) { wp_send_json_success(['history' => $history]); } else { wp_send_json_error(['message' => __('Could not retrieve history.', 'advanced-ip-blocker')]); } } /** * AJAX callback to test the server's outbound connection. */ public function ajax_test_outbound_connection() { if (! current_user_can('advaipbl_manage_settings')) { wp_send_json_error([ 'message' => 'Permission denied.' ]); } check_ajax_referer('advaipbl_test_connection_nonce', 'nonce'); $response = wp_remote_get('https://api.ipify.org?format=json', [ 'timeout' => 10 ]); if (is_wp_error($response)) { wp_send_json_error([ 'message' => 'Error: ' . $response->get_error_message() ]); } $http_code = wp_remote_retrieve_response_code($response); if ($http_code !== 200) { wp_send_json_error([ 'message' => sprintf('Error: Received HTTP status code %d.', $http_code) ]); } $body = json_decode(wp_remote_retrieve_body($response), true); if (isset($body['ip']) && filter_var($body['ip'], FILTER_VALIDATE_IP)) { wp_send_json_success([ 'message' => sprintf('Success! Connection established from IP: %s', $body['ip']) ]); } wp_send_json_error([ 'message' => 'Error: The response from the test service was invalid.' ]); } /** * AJAX callback to add a specific IP to the whitelist. * This is used by the interactive buttons in the admin interface. */ public function ajax_add_ip_to_whitelist() { if (! current_user_can('advaipbl_manage_settings')) { wp_send_json_error([ 'message' => __('Permission denied.', 'advanced-ip-blocker') ]); } check_ajax_referer('advaipbl_add_whitelist_nonce', 'nonce'); if (! isset($_POST['ip']) || ! filter_var(wp_unslash($_POST['ip']), FILTER_VALIDATE_IP)) { wp_send_json_error([ 'message' => __('Invalid or missing IP address.', 'advanced-ip-blocker') ]); } $ip = sanitize_text_field(wp_unslash($_POST['ip'])); $detail = isset($_POST['detail']) ? sanitize_text_field(wp_unslash($_POST['detail'])) : __('Added via admin action', 'advanced-ip-blocker'); $success = $this->plugin->add_to_whitelist_and_unblock($ip, $detail); if ($success) { /* translators: %s is a placeholder */ wp_send_json_success([ 'message' => sprintf(__('%s successfully added to the whitelist.', 'advanced-ip-blocker'), $ip) ]); } else { /* translators: %s is a placeholder */ wp_send_json_success([ 'message' => sprintf(__('%s is already whitelisted.', 'advanced-ip-blocker'), $ip) ]); } } /** * AJAX callback to verify a geolocation or Cloudflare API key. */ public function ajax_verify_api_key() { if (! current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_verify_api_nonce', 'nonce'); $provider = isset($_POST['provider']) ? sanitize_text_field(wp_unslash($_POST['provider'])) : ''; $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : ''; if (empty($provider)) { wp_send_json_error(['message' => __('Provider is missing.', 'advanced-ip-blocker')]); } if ($provider === 'cloudflare') { if (empty($api_key)) { wp_send_json_error(['message' => __('API Token is missing.', 'advanced-ip-blocker')]); } $result = $this->plugin->cloudflare_manager->verify_token($api_key); if (is_wp_error($result)) { wp_send_json_error(['message' => $result->get_error_message()]); } else { wp_send_json_success(['message' => __('Token verified successfully! (Status: Active)', 'advanced-ip-blocker')]); } return; } if ($provider === 'api_token_v3') { if (empty($api_key)) { $this->plugin->log_event('AIB Network connection failed: API Key is missing.', 'error'); wp_send_json_error(['message' => __('API Key is missing.', 'advanced-ip-blocker')]); } $response = wp_remote_get('https://advaipbl.com/wp-json/aib-api/v3/verify-token?v=' . ADVAIPBL_VERSION, [ 'headers' => [ 'Authorization' => 'Bearer ' . $api_key, 'X-AIB-Auth' => 'Bearer ' . $api_key, 'Accept' => 'application/json' ], 'timeout' => 10 ]); if (is_wp_error($response)) { $this->plugin->log_event('AIB Network connection failed: ' . $response->get_error_message(), 'error'); wp_send_json_error(['message' => __('Connection failed: ', 'advanced-ip-blocker') . $response->get_error_message()]); } $status_code = wp_remote_retrieve_response_code($response); $body = wp_remote_retrieve_body($response); $data = json_decode($body, true); if ($status_code === 200 && isset($data['status']) && in_array($data['status'], ['active', 'connected'], true)) { $this->plugin->log_event('AIB Network connection verified successfully. API Key is active.', 'info'); wp_send_json_success(['message' => __('API Key is valid and active!', 'advanced-ip-blocker')]); } else { $error_msg = $data['message'] ?? __('Invalid or inactive API Key.', 'advanced-ip-blocker'); $this->plugin->log_event('AIB Network connection failed: ' . $error_msg, 'error'); wp_send_json_error(['message' => $error_msg]); } return; } $this->plugin->geolocation_manager->set_transient_api_key($provider, $api_key); $result = $this->plugin->geolocation_manager->fetch_location('8.8.8.8'); $this->plugin->geolocation_manager->clear_transient_api_key($provider); if ($result && !isset($result['error'])) { wp_send_json_success(['message' => __('API Key is valid!', 'advanced-ip-blocker')]); } else { $error_message = $result['error_message'] ?? __('Invalid API Key or connection error.', 'advanced-ip-blocker'); wp_send_json_error(['message' => $error_message]); } } /** * AJAX action to get a free API Key from the Central Server automatically. */ public function ajax_get_free_api_key() { check_ajax_referer('advaipbl_verify_api_nonce', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Unauthorized', 'advanced-ip-blocker')]); } $result = $this->plugin->community_manager->register_site(); if (is_wp_error($result)) { wp_send_json_error(['message' => __('Connection to Central Server failed: ', 'advanced-ip-blocker') . $result->get_error_message()]); } if (isset($result['api_token'])) { $this->plugin->community_manager->update_list(); wp_send_json_success([ 'message' => __('API Key generated and saved successfully!', 'advanced-ip-blocker'), 'api_token_visual' => 'AIB_' . str_repeat('•', 24) . substr($result['api_token'], -4) ]); } else { wp_send_json_error(['message' => __('Failed to generate API Key.', 'advanced-ip-blocker')]); } } /** * AJAX callback to handle the telemetry notice response. */ public function ajax_handle_telemetry_notice() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(); } check_ajax_referer('advaipbl_telemetry_nonce', 'nonce'); $action = isset($_POST['telemetry_action']) ? sanitize_key($_POST['telemetry_action']) : ''; if ('allow' === $action) { $options = $this->plugin->options; $options['allow_telemetry'] = '1'; update_option(ADVAIPBL_Main::OPTION_SETTINGS, $options); update_option('advaipbl_telemetry_notice_dismissed', '1'); if (!wp_next_scheduled('advaipbl_send_telemetry_data_event')) { wp_schedule_event(time() + DAY_IN_SECONDS, 'weekly', 'advaipbl_send_telemetry_data_event'); $this->plugin->log_event('Telemetry cron job scheduled after user consent.', 'info'); } wp_send_json_success(); } elseif ('dismiss' === $action) { update_option('advaipbl_telemetry_notice_dismissed', '1'); wp_clear_scheduled_hook('advaipbl_send_telemetry_data_event'); wp_send_json_success(); } wp_send_json_error(); } /** * AJAX callback to generate a new 2FA secret for a user. */ public function ajax_2fa_generate() { check_ajax_referer('advaipbl_2fa_generate_nonce', 'nonce'); $user_id = isset($_POST['user_id']) ? absint($_POST['user_id']) : 0; if (! $user_id || ! current_user_can('edit_user', $user_id)) { wp_send_json_error([ 'message' => __('Permission denied.', 'advanced-ip-blocker') ]); } $user = get_user_by('id', $user_id); if (! $user) { wp_send_json_error([ 'message' => __('Invalid user.', 'advanced-ip-blocker') ]); } $data = $this->plugin->tfa_manager->generate_new_secret_for_user($user); wp_send_json_success($data); } /** * AJAX callback to verify and activate 2FA for a user. */ public function ajax_2fa_activate() { check_ajax_referer('advaipbl_2fa_activate_nonce', 'nonce'); $user_id = isset($_POST['user_id']) ? absint($_POST['user_id']) : 0; $code = isset($_POST['code']) ? sanitize_text_field(wp_unslash($_POST['code'])) : ''; $backup_codes = isset($_POST['backup_codes']) && is_array($_POST['backup_codes']) ? array_map('sanitize_text_field', wp_unslash($_POST['backup_codes'])) : []; if (! $user_id || ! current_user_can('edit_user', $user_id)) { wp_send_json_error([ 'message' => __('Permission denied.', 'advanced-ip-blocker') ]); } $success = $this->plugin->tfa_manager->verify_and_activate($user_id, $code, $backup_codes); if ($success) { wp_send_json_success(); } else { wp_send_json_error([ 'message' => __('Invalid verification code. Please try again.', 'advanced-ip-blocker') ]); } } /** * AJAX callback to deactivate 2FA for a user. */ public function ajax_2fa_deactivate() { check_ajax_referer('advaipbl_2fa_deactivate_nonce', 'nonce'); $user_id = isset($_POST['user_id']) ? absint($_POST['user_id']) : 0; if (! $user_id || ! current_user_can('edit_user', $user_id)) { wp_send_json_error([ 'message' => __('Permission denied.', 'advanced-ip-blocker') ]); } $this->plugin->tfa_manager->deactivate_for_user($user_id); wp_send_json_success(); } /** * AJAX callback to start the GeoIP database download. */ public function ajax_update_geoip_db() { if (! isset($_POST['nonce']) || ! wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nonce'])), 'advaipbl_update_geoip_nonce')) { wp_send_json_error(['message' => 'Nonce verification failed.'], 403); } if (! current_user_can('manage_options') || ! $this->plugin->geoip_manager) { wp_send_json_error(['message' => 'Permission denied or module not available.'], 403); } // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged set_time_limit(300); $this->plugin->log_event('Starting manual GeoIP database update from Dashboard.', 'info'); $result = $this->plugin->geoip_manager->download_and_unpack_databases(); if ($result['success']) { $this->plugin->log_event('Manual GeoIP database update completed successfully.', 'info'); wp_send_json_success(['message' => $result['message']]); } else { $this->plugin->log_event('Manual GeoIP database update failed: ' . $result['message'], 'error'); wp_send_json_error(['message' => $result['message']]); } } /** * AJAX callback to get advanced rules, with pagination support. */ public function ajax_get_advanced_rules() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_get_rules_nonce', 'nonce'); if (ob_get_level()) { ob_clean(); } if (isset($_POST['rule_id'])) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash $rule_id = sanitize_text_field($_POST['rule_id']); $all_rules = $this->plugin->rules_engine->get_rules(); $found_rule = null; foreach ($all_rules as $r) { if (isset($r['id']) && $r['id'] === $rule_id) { $found_rule = $r; break; } } if ($found_rule) { if (isset($this->plugin->rules_metrics)) { $found_rule['metrics'] = $this->plugin->rules_metrics->get_rule_metrics($found_rule['id']); } wp_send_json_success(['rules' => [$found_rule]]); } else { wp_send_json_error(['message' => __('Rule not found.', 'advanced-ip-blocker')]); } } $page = isset($_POST['page']) ? absint($_POST['page']) : 1; $per_page = 20; $all_rules = $this->plugin->rules_engine->get_rules(); $all_rules = is_array($all_rules) ? $all_rules : []; $total_items = count($all_rules); $total_pages = ceil($total_items / $per_page); $rules_for_page = array_slice($all_rules, ($page - 1) * $per_page, $per_page); if (isset($this->plugin->rules_metrics)) { foreach ($rules_for_page as &$rule) { if (isset($rule['id'])) { $rule['metrics'] = $this->plugin->rules_metrics->get_rule_metrics($rule['id']); } else { $rule['metrics'] = []; } } } wp_send_json_success([ 'rules' => $rules_for_page, 'pagination' => [ 'total_items' => $total_items, 'total_pages' => $total_pages, 'current_page' => $page, ] ]); wp_die(); } /** * AJAX callback to save (create or update) an advanced rule. */ public function ajax_save_advanced_rule() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_save_rule_nonce', 'nonce'); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $rule_data = isset($_POST['rule']) ? json_decode(wp_unslash($_POST['rule']), true) : null; if (json_last_error() !== JSON_ERROR_NONE || !is_array($rule_data)) { wp_send_json_error(['message' => __('Invalid rule data received.', 'advanced-ip-blocker')]); } $rule_id = $rule_data['id'] ?? null; if (empty($rule_id)) { $saved_rule = $this->plugin->rules_engine->add_rule($rule_data); if ($saved_rule) { wp_send_json_success(['message' => __('Rule created successfully.', 'advanced-ip-blocker'), 'rule' => $saved_rule]); } else { wp_send_json_error(['message' => __('Failed to create rule.', 'advanced-ip-blocker')]); } } else { if ($this->plugin->rules_engine->update_rule($rule_id, $rule_data)) { wp_send_json_success(['message' => __('Rule updated successfully.', 'advanced-ip-blocker'), 'rule' => $rule_data]); } else { wp_send_json_error(['message' => __('Failed to update rule. It may not exist.', 'advanced-ip-blocker')]); } } } public function ajax_toggle_advanced_rule() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_save_rule_nonce', 'nonce'); $rule_id = isset($_POST['rule_id']) ? sanitize_key($_POST['rule_id']) : ''; $is_active = isset($_POST['is_active']) ? (int)$_POST['is_active'] === 1 : true; if (empty($rule_id)) { wp_send_json_error(['message' => __('Invalid rule ID.', 'advanced-ip-blocker')]); } $rules = $this->plugin->rules_engine->get_rules(); $target_rule = null; foreach ($rules as $rule) { if ($rule['id'] === $rule_id) { $target_rule = $rule; break; } } if ($target_rule) { $target_rule['is_active'] = $is_active; if ($this->plugin->rules_engine->update_rule($rule_id, $target_rule)) { wp_send_json_success(['message' => __('Rule toggled successfully.', 'advanced-ip-blocker')]); } else { wp_send_json_error(['message' => __('Failed to save rule state.', 'advanced-ip-blocker')]); } } else { wp_send_json_error(['message' => __('Rule not found.', 'advanced-ip-blocker')]); } } /** * AJAX callback to delete an advanced rule. */ public function ajax_delete_advanced_rule() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_delete_rule_nonce', 'nonce'); $rule_id = isset($_POST['rule_id']) ? sanitize_text_field(wp_unslash($_POST['rule_id'])) : null; if (empty($rule_id)) { wp_send_json_error(['message' => __('Invalid rule ID.', 'advanced-ip-blocker')]); } if (strpos($rule_id, 'ar_zd_') === 0) { wp_send_json_error(['message' => __('Cloud rules are centrally managed and cannot be deleted from the local plugin.', 'advanced-ip-blocker')]); } elseif ($this->plugin->rules_engine->delete_rule($rule_id)) { wp_send_json_success(['message' => __('Rule deleted successfully.', 'advanced-ip-blocker')]); } else { wp_send_json_error(['message' => __('Failed to delete rule. It may have already been deleted.', 'advanced-ip-blocker')]); } } /** * AJAX callback to bulk delete advanced rules. */ public function ajax_bulk_delete_advanced_rules() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_bulk_delete_rules_nonce', 'nonce'); $rule_ids = isset($_POST['rule_ids']) && is_array($_POST['rule_ids']) ? array_map('sanitize_text_field', wp_unslash($_POST['rule_ids'])) : []; if (empty($rule_ids)) { wp_send_json_error(['message' => __('No rules selected.', 'advanced-ip-blocker')]); wp_die(); } $deleted_count = 0; foreach ($rule_ids as $rule_id) { if ($this->plugin->rules_engine->delete_rule($rule_id)) { $deleted_count++; } } if ($deleted_count > 0) { /* translators: %s is a placeholder */ $message = sprintf(_n('%d rule deleted successfully.', '%d rules deleted successfully.', $deleted_count, 'advanced-ip-blocker'), $deleted_count); wp_send_json_success(['message' => $message]); } else { wp_send_json_error(['message' => __('Failed to delete the selected rules.', 'advanced-ip-blocker')]); } wp_die(); } /** * AJAX callback to verify an AbuseIPDB API key. */ public function ajax_verify_abuseipdb_key() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_verify_abuseipdb_nonce', 'nonce'); $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : ''; $result = $this->plugin->abuseipdb_manager->verify_api_key($api_key); if ($result['success']) { wp_send_json_success(['message' => $result['message']]); } else { wp_send_json_error(['message' => $result['message']]); } wp_die(); } /** * AJAX callback to execute the deep vulnerability scan. */ public function ajax_run_deep_scan() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_deep_scan_nonce', 'nonce'); if (!isset($this->plugin->site_scanner)) { require_once plugin_dir_path(__FILE__) . 'class-advaipbl-site-scanner.php'; $this->plugin->site_scanner = new ADVAIPBL_Site_Scanner($this->plugin); } $result = $this->plugin->site_scanner->check_vulnerabilities_via_api(); if (isset($result['status']) && $result['status'] === 'error') { wp_send_json_error(['message' => __('API connection failed. Please try again later.', 'advanced-ip-blocker')]); } wp_send_json_success($result); } /** * AJAX callback to check server reputation. */ public function ajax_check_server_reputation() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_reputation_nonce', 'nonce'); if (!isset($this->plugin->site_scanner)) { require_once plugin_dir_path(__FILE__) . 'class-advaipbl-site-scanner.php'; $this->plugin->site_scanner = new ADVAIPBL_Site_Scanner($this->plugin); } $result = $this->plugin->site_scanner->check_server_reputation(); if (isset($result['status']) && $result['status'] === 'error') { wp_send_json_error(['message' => $result['message']]); } wp_send_json_success($result); } /** * Ajax handler to reorder advanced rules. */ public function ajax_reorder_advanced_rules() { check_ajax_referer('advaipbl_reorder_rules_nonce', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } $rule_id = isset($_POST['rule_id']) ? sanitize_text_field(wp_unslash($_POST['rule_id'])) : ''; $direction = isset($_POST['direction']) ? sanitize_text_field(wp_unslash($_POST['direction'])) : ''; if (empty($rule_id) || !in_array($direction, ['up', 'down'], true)) { wp_send_json_error(['message' => __('Invalid parameters.', 'advanced-ip-blocker')]); } $rules = $this->plugin->rules_engine->get_rules(); $rules = array_values($rules); $target_index = -1; foreach ($rules as $index => $rule) { if (isset($rule['id']) && $rule['id'] === $rule_id) { $target_index = $index; break; } } if ($target_index === -1) { wp_send_json_error(['message' => __('Rule not found.', 'advanced-ip-blocker')]); } if ($direction === 'up') { if ($target_index > 0 && isset($rules[$target_index - 1])) { $temp = $rules[$target_index - 1]; $rules[$target_index - 1] = $rules[$target_index]; $rules[$target_index] = $temp; } } elseif ($direction === 'down') { if ($target_index < count($rules) - 1 && isset($rules[$target_index + 1])) { $temp = $rules[$target_index + 1]; $rules[$target_index + 1] = $rules[$target_index]; $rules[$target_index] = $temp; } } update_option(ADVAIPBL_Rules_Engine::OPTION_RULES, $rules); wp_send_json_success(['message' => __('Rule reordered successfully.', 'advanced-ip-blocker')]); } /** * AJAX action to clear audit logs. */ public function ajax_clear_audit_logs() { check_ajax_referer('advaipbl_clear_audit_logs_nonce', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } if (!isset($this->plugin->audit_logger)) { wp_send_json_error(['message' => __('Audit Logger not active.', 'advanced-ip-blocker')]); } $result = $this->plugin->audit_logger->clear_all_logs(); if ($result !== false) { /* translators: %s is a placeholder */ $this->plugin->log_event(sprintf(__('Audit logs manually cleared by %s.', 'advanced-ip-blocker'), $this->plugin->get_current_admin_username()), 'warning'); wp_send_json_success(['message' => __('Audit logs cleared successfully.', 'advanced-ip-blocker')]); } else { wp_send_json_error(['message' => __('Failed to clear logs.', 'advanced-ip-blocker')]); } } /** * AJAX Handler for manual FIM Scan. */ public function ajax_run_fim_scan() { check_ajax_referer('advaipbl_run_fim_scan_nonce', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } if (empty($this->plugin->options['enable_fim'])) { wp_send_json_error(['message' => __('File Integrity Monitor is disabled.', 'advanced-ip-blocker')]); } if (!isset($this->plugin->file_verifier)) { wp_send_json_error(['message' => __('File Verifier module not loaded.', 'advanced-ip-blocker')]); } $this->plugin->check_fim_signatures_version(); $changes = $this->plugin->file_verifier->scan_files(); if (empty($changes)) { wp_send_json_success(['message' => __('Scan complete. No changes detected.', 'advanced-ip-blocker')]); } else { $count = count($changes); /* translators: %s is a placeholder */ $msg = sprintf(_n('Scan complete. %d file change detected (Alert sent).', 'Scan complete. %d file changes detected (Alert sent).', $count, 'advanced-ip-blocker'), $count); wp_send_json_success(['message' => $msg]); } } /** * AJAX callback for Bulk Import of IPs to Whitelist. */ public function ajax_bulk_import_whitelist() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_bulk_import_whitelist_nonce', 'nonce'); $raw_data = isset($_POST['ip_list']) ? sanitize_textarea_field(wp_unslash($_POST['ip_list'])) : ''; $detail = isset($_POST['detail']) ? sanitize_text_field(wp_unslash($_POST['detail'])) : __('Bulk Import', 'advanced-ip-blocker'); if (empty($raw_data)) { wp_send_json_error(['message' => __('No data provided.', 'advanced-ip-blocker')]); } $lines = preg_split('/\r\n|\r|\n/', $raw_data); $imported_count = 0; $skipped_count = 0; $errors = []; foreach ($lines as $line) { $ip_or_range = trim($line); if (empty($ip_or_range)) { continue; } if ($this->plugin->add_to_whitelist_and_unblock($ip_or_range, $detail)) { $imported_count++; } else { $skipped_count++; } } if ($imported_count > 0) { $this->plugin->purge_all_page_caches(); } $message = sprintf( /* translators: %s is a placeholder */ __('Import complete. Imported: %1$d. Skipped/Invalid/Duplicate: %2$d.', 'advanced-ip-blocker'), $imported_count, $skipped_count ); wp_send_json_success(['message' => $message, 'imported' => $imported_count, 'skipped' => $skipped_count]); } /** * AJAX callback for Bulk Export of Whitelisted IPs. */ public function ajax_bulk_export_whitelist() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_bulk_export_whitelist_nonce', 'nonce'); $include_details = isset($_POST['include_details']) && $_POST['include_details'] === 'true'; $whitelist = get_option(ADVAIPBL_Main::OPTION_WHITELIST, []); if (empty($whitelist)) { wp_send_json_error(['message' => __('Whitelist is empty.', 'advanced-ip-blocker')]); } $export_data = ""; if ($include_details) { $export_data .= "IP,Detail,Date\n"; foreach ($whitelist as $key => $entry) { $ip = ''; $detail = ''; $date = ''; if (filter_var($key, FILTER_VALIDATE_IP) || strpos($key, '/') !== false) { $ip = $key; if (is_array($entry)) { $detail = isset($entry['detail']) ? $entry['detail'] : ''; $ts = $entry['timestamp'] ?? $entry['created_at'] ?? ''; $date = $ts ? gmdate('Y-m-d H:i:s', $ts) : ''; } } elseif (is_array($entry) && isset($entry['ip'])) { $ip = $entry['ip']; $detail = isset($entry['detail']) ? $entry['detail'] : ''; $ts = $entry['timestamp'] ?? $entry['created_at'] ?? ''; $date = $ts ? gmdate('Y-m-d H:i:s', $ts) : ''; } elseif (is_string($entry)) { $ip = $entry; } if (!empty($ip)) { $detail_csv = '"' . str_replace('"', '""', $detail) . '"'; $export_data .= "{$ip},{$detail_csv},{$date}\n"; } } $filename = 'aib-whitelist-export-' . gmdate('Y-m-d') . '.csv'; $content_type = 'text/csv'; } else { foreach ($whitelist as $key => $entry) { $ip = ''; if (filter_var($key, FILTER_VALIDATE_IP) || strpos($key, '/') !== false) { $ip = $key; } elseif (is_array($entry) && isset($entry['ip'])) { $ip = $entry['ip']; } elseif (is_string($entry)) { $ip = $entry; } if (!empty($ip)) { $export_data .= $ip . "\n"; } } $filename = 'aib-whitelist-export-' . gmdate('Y-m-d') . '.txt'; $content_type = 'text/plain'; } $base64_data = base64_encode($export_data); $data_uri = 'data:' . $content_type . ';base64,' . $base64_data; wp_send_json_success(['file_url' => $data_uri, 'filename' => $filename]); } /** * AJAX callback for Bulk Import of Blocked IPs. */ public function ajax_bulk_import_blocked_ips() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_bulk_import_blocked_ips_nonce', 'nonce'); $raw_data = isset($_POST['ip_list']) ? sanitize_textarea_field(wp_unslash($_POST['ip_list'])) : ''; $duration_minutes = isset($_POST['duration']) ? intval($_POST['duration']) : 0; $hardcoded_reason = __('Bulk Import', 'advanced-ip-blocker'); if (empty($raw_data)) { wp_send_json_error(['message' => __('No data provided.', 'advanced-ip-blocker')]); } $current_time = time(); $expires_at = 0; if ($duration_minutes > 0) { $expires_at = $current_time + ($duration_minutes * 60); } $lines = preg_split('/\r\n|\r|\n/', $raw_data); $imported_count = 0; $skipped_count = 0; $invalid_count = 0; global $wpdb; $table_name = $wpdb->prefix . 'advaipbl_blocked_ips'; foreach ($lines as $line) { $line = trim($line); if (empty($line)) { continue; } $parsed = str_getcsv($line); $ip_or_range = isset($parsed[0]) ? trim($parsed[0]) : ''; if (empty($ip_or_range) || strtolower($ip_or_range) === 'ip/cidr') { continue; } if (!$this->plugin->is_valid_ip_or_range($ip_or_range)) { $invalid_count++; continue; } $item_reason = $hardcoded_reason; $item_expires_at = $expires_at; if (isset($parsed[2]) && trim($parsed[2]) !== '') { $csv_exp = trim($parsed[2]); if (strtolower($csv_exp) === 'permanent' || $csv_exp == '0') { $item_expires_at = 0; } else { $parsed_time = strtotime($csv_exp); if ($parsed_time !== false) { if ($parsed_time > $current_time) { $item_expires_at = $parsed_time; } else { $item_expires_at = 0; } } elseif (is_numeric($csv_exp) && $csv_exp > 0) { $item_expires_at = intval($csv_exp); } } } if ($this->plugin->is_whitelisted($ip_or_range)) { $skipped_count++; continue; } $query = "SELECT COUNT(*) FROM {$table_name} WHERE ip_range = %s AND (expires_at = 0 OR expires_at > %d)"; // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter $exists = $wpdb->get_var($wpdb->prepare($query, $ip_or_range, $current_time)); if ($exists) { $skipped_count++; continue; } // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery $inserted = $wpdb->insert( $table_name, [ 'ip_range' => $ip_or_range, 'block_type' => 'bulk_import', 'timestamp' => $current_time, 'expires_at' => $item_expires_at, 'reason' => $item_reason ], ['%s', '%s', '%d', '%d', '%s'] ); if ($inserted) { $imported_count++; } else { $skipped_count++; } } if ($imported_count > 0 && !empty($this->plugin->options['enable_htaccess_ip_blocking'])) { $this->plugin->htaccess_manager->update_htaccess(); } if ($imported_count > 0) { $this->plugin->purge_all_page_caches(); $this->plugin->update_db_cidrs_cache(); } if ($imported_count > 0 && !empty($this->plugin->options['enable_cloudflare'])) { if (!wp_next_scheduled('advaipbl_cloudflare_sync_event')) { wp_schedule_single_event(time(), 'advaipbl_cloudflare_sync_event'); } } $message = sprintf( /* translators: %s is a placeholder */ __('Import complete. Imported: %1$d. Skipped/Invalid/Duplicate: %2$d.', 'advanced-ip-blocker'), $imported_count, $skipped_count + $invalid_count ); wp_send_json_success(['message' => $message, 'imported' => $imported_count, 'skipped' => $skipped_count, 'invalid' => $invalid_count]); } /** * AJAX callback for Bulk Export of Blocked IPs. */ public function ajax_bulk_export_blocked_ips() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } check_ajax_referer('advaipbl_bulk_export_blocked_ips_nonce', 'nonce'); global $wpdb; $table_name = $wpdb->prefix . 'advaipbl_blocked_ips'; $current_time = time(); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter $results = $wpdb->get_results($wpdb->prepare("SELECT ip_range, reason, expires_at, block_type FROM {$table_name} WHERE expires_at = 0 OR expires_at > %d", $current_time), ARRAY_A); if (empty($results)) { wp_send_json_error(['message' => __('No active blocked IPs found to export.', 'advanced-ip-blocker')]); } $export_data = "IP/CIDR,Reason,Expiration,Type\n"; foreach ($results as $row) { $reason_csv = '"' . str_replace('"', '""', $row['reason']) . '"'; $expiration = ($row['expires_at'] == 0) ? 'Permanent' : gmdate('Y-m-d H:i:s', $row['expires_at']); $export_data .= "{$row['ip_range']},{$reason_csv},{$expiration},{$row['block_type']}\n"; } $filename = 'aib-blocked-ips-export-' . gmdate('Y-m-d') . '.csv'; $content_type = 'text/csv'; $base64_data = base64_encode($export_data); $data_uri = 'data:' . $content_type . ';base64,' . $base64_data; wp_send_json_success(['file_url' => $data_uri, 'filename' => $filename]); } /** * AJAX callback for Exporting Advanced Rules securely. */ public function ajax_export_advanced_rules() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_export_adv_rules_nonce', 'nonce'); $rules = $this->plugin->rules_engine->get_rules(); if (empty($rules)) { wp_send_json_error(['message' => __('No rules exist to export.', 'advanced-ip-blocker')]); wp_die(); } $export_payload = [ '_advaipbl_export' => true, 'export_version' => '1.0', 'generated_at' => current_time('mysql'), 'source_site' => site_url(), 'rules' => $rules ]; wp_send_json_success([ 'payload' => $export_payload, 'filename' => 'aib-advanced-rules-export-' . gmdate('Y-m-d') . '.json' ]); wp_die(); } public function ajax_export_selected_advanced_rules() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_export_adv_rules_nonce', 'nonce'); $rule_ids = isset($_POST['rule_ids']) && is_array($_POST['rule_ids']) ? array_map('sanitize_text_field', wp_unslash($_POST['rule_ids'])) : []; if (empty($rule_ids)) { wp_send_json_error(['message' => __('No rules selected.', 'advanced-ip-blocker')]); wp_die(); } $all_rules = $this->plugin->rules_engine->get_rules(); $selected_rules = []; foreach ($all_rules as $rule) { if (in_array($rule['id'], $rule_ids, true)) { $selected_rules[] = $rule; } } if (empty($selected_rules)) { wp_send_json_error(['message' => __('Selected rules could not be found.', 'advanced-ip-blocker')]); wp_die(); } $export_payload = [ '_advaipbl_export' => true, 'export_version' => '1.0', 'generated_at' => current_time('mysql'), 'source_site' => site_url(), 'rules' => $selected_rules ]; wp_send_json_success([ 'payload' => $export_payload, 'filename' => 'aib-selected-rules-export-' . gmdate('Y-m-d') . '.json' ]); wp_die(); } /** * AJAX callback for Importing Advanced Rules securely. */ public function ajax_import_advanced_rules() { if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); wp_die(); } check_ajax_referer('advaipbl_import_adv_rules_nonce', 'nonce'); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash $raw_json = isset($_POST['json_payload']) ? trim(wp_unslash($_POST['json_payload'])) : ''; if (empty($raw_json)) { wp_send_json_error(['message' => __('No payload provided.', 'advanced-ip-blocker')]); wp_die(); } $parsed_data = json_decode($raw_json, true); if (json_last_error() !== JSON_ERROR_NONE || !is_array($parsed_data)) { wp_send_json_error(['message' => __('Invalid JSON syntax.', 'advanced-ip-blocker')]); wp_die(); } if (empty($parsed_data['_advaipbl_export']) || $parsed_data['_advaipbl_export'] !== true || empty($parsed_data['rules']) || !is_array($parsed_data['rules'])) { wp_send_json_error(['message' => __('JSON validation failed: This file is not a valid Advanced Rules export.', 'advanced-ip-blocker')]); wp_die(); } $imported_count = 0; $ignored_count = 0; $skipped_count = 0; $existing_rules = $this->plugin->rules_engine->get_rules(); foreach ($parsed_data['rules'] as $rule) { $incoming_hash = md5(json_encode([ 'name' => $rule['name'] ?? '', 'action' => $rule['action'] ?? '', 'conditions' => $rule['conditions'] ?? [] ])); $is_duplicate = false; foreach ($existing_rules as $existing_rule) { $existing_hash = md5(json_encode([ 'name' => $existing_rule['name'] ?? '', 'action' => $existing_rule['action'] ?? '', 'conditions' => $existing_rule['conditions'] ?? [] ])); if ($incoming_hash === $existing_hash) { $is_duplicate = true; break; } } if ($is_duplicate) { $skipped_count++; continue; } unset($rule['id']); $saved_rule = $this->plugin->rules_engine->add_rule($rule); if ($saved_rule) { $imported_count++; $existing_rules[] = $saved_rule; } else { $ignored_count++; } } if ($imported_count > 0 || $skipped_count > 0) { $msg = []; if ($imported_count > 0) { /* translators: %s is a placeholder */ $msg[] = sprintf(__('Imported %d new rules.', 'advanced-ip-blocker'), $imported_count); } if ($skipped_count > 0) { /* translators: %s is a placeholder */ $msg[] = sprintf(__('Skipped %d duplicate rules.', 'advanced-ip-blocker'), $skipped_count); } if ($ignored_count > 0) { /* translators: %s is a placeholder */ $msg[] = sprintf(__('Ignored %d invalid rules.', 'advanced-ip-blocker'), $ignored_count); } wp_send_json_success(['message' => implode(' ', $msg)]); } else { wp_send_json_error(['message' => __('Failed to import. No valid or new rules were found.', 'advanced-ip-blocker')]); } wp_die(); } /** * AJAX callback to forcefully run a specific WP-Cron event. */ public function ajax_force_run_cron() { check_ajax_referer('advaipbl_admin_nonce_action', 'nonce'); if (!current_user_can('advaipbl_manage_settings')) { wp_send_json_error(['message' => __('Permission denied.', 'advanced-ip-blocker')]); } $hook = isset($_POST['hook']) ? sanitize_text_field(wp_unslash($_POST['hook'])) : ''; $sig = isset($_POST['sig']) ? sanitize_text_field(wp_unslash($_POST['sig'])) : ''; if (empty($hook)) { wp_send_json_error(['message' => __('Invalid cron hook.', 'advanced-ip-blocker')]); } $args = []; if (!empty($sig)) { $crons = _get_cron_array(); foreach ($crons as $timestamp => $hooks) { if (isset($hooks[$hook][$sig])) { $args = $hooks[$hook][$sig]['args'] ?? []; break; } } } try { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound if (!defined('DOING_CRON')) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound define('DOING_CRON', true); } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound do_action_ref_array($hook, $args); /* translators: %s is a placeholder */ $msg = sprintf(__('Cron event "%s" successfully executed.', 'advanced-ip-blocker'), $hook); /* translators: %s is a placeholder */ $log_msg = sprintf(__('Manual WP-Cron trigger: %1$s was forced to run by %2$s.', 'advanced-ip-blocker'), $hook, $this->plugin->get_current_admin_username()); $this->plugin->log_event($log_msg, 'info'); global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->insert( $wpdb->prefix . 'advaipbl_logs', [ 'timestamp' => current_time('mysql', 1), 'ip' => $this->plugin->get_client_ip(), 'log_type' => 'wp_cron', 'details' => wp_json_encode([ 'source' => 'Manual (Admin)', 'url' => 'wp-admin/admin-ajax.php (Forced)', 'due_hooks' => [$hook], 'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? sanitize_text_field(wp_unslash($_SERVER['HTTP_USER_AGENT'])) : '', ]) ] ); wp_send_json_success(['message' => $msg]); } catch (Throwable $e) { /* translators: %s is a placeholder */ $error_msg = sprintf(__('Error forcing WP-Cron %1$s: %2$s', 'advanced-ip-blocker'), $hook, $e->getMessage()); $this->plugin->log_event($error_msg, 'error'); wp_send_json_error(['message' => __('An error occurred while running the task. Check the plugin error log.', 'advanced-ip-blocker')]); } } }