plugin = $plugin_instance; } public function ajax_get_dashboard_stats() { // 1. Verificamos el nonce. El primer argumento debe coincidir con la acción del nonce que creamos. check_ajax_referer('wp_ajax_advaipbl_get_dashboard_stats', 'nonce'); if (!current_user_can('manage_options')) { 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 para resetear la puntuación de amenaza de una IP. */ public function ajax_reset_threat_score() { if (!current_user_can('manage_options')) { 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) { /* translators: %1$s: IP, %2$s: Username. */ $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 para añadir una firma a la lista blanca y eliminarla de la lista de bloqueo. */ public function ajax_whitelist_signature() { if (!current_user_can('manage_options')) { 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')]); } // 1. Obtenemos los detalles de la firma para construir los comentarios. $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')]); } // 2. Construimos la entrada para la lista blanca con comentarios. $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); // 3. Obtenemos el array COMPLETO de settings, modificamos la clave y guardamos. $options = get_option(self::OPTION_SETTINGS, []); $current_whitelist = $options['trusted_signature_hashes'] ?? ''; $new_whitelist = $current_whitelist . "\n" . $entry_to_add; // Actualizamos la clave dentro del array de opciones. $options['trusted_signature_hashes'] = trim($new_whitelist); // Guardamos el array de opciones completo. update_option(self::OPTION_SETTINGS, $options); // 4. Eliminamos la firma de la lista de maliciosos. $this->plugin->fingerprint_manager->delete_signature($hash); /* translators: %s: hash, %s: Username. */ $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 para eliminar una firma maliciosa. */ public function ajax_delete_signature() { if (!current_user_can('manage_options')) { 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'])) : ''; // Validamos que el hash tenga la longitud correcta de un sha256. 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: %1$s: Hash, %2$s: Username */ $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 para obtener los detalles de una firma maliciosa. */ public function ajax_get_signature_details() { if (!current_user_can('manage_options')) { 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 para obtener los detalles de un Endpoint Lockdown. */ public function ajax_get_lockdown_details() { if (!current_user_can('manage_options')) { 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'; $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 para obtener el historial de eventos de una IP. */ public function ajax_get_score_history() { if (!current_user_can('manage_options')) { 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('manage_options') ) { 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() { // 1. Validar permisos y nonce de seguridad (esto no cambia). if ( ! current_user_can('manage_options') ) { wp_send_json_error( [ 'message' => __( 'Permission denied.', 'advanced-ip-blocker' ) ] ); } check_ajax_referer( 'advaipbl_add_whitelist_nonce', 'nonce' ); // 2. Obtener y validar la IP del POST. Esta función AJAX solo maneja IPs individuales. 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'); // 3. Reutilizar nuestra nueva lógica centralizada. $success = $this->plugin->add_to_whitelist_and_unblock( $ip, $detail ); if ( $success ) { /* translators: %s: The IP address that was successfully whitelisted. */ wp_send_json_success( [ 'message' => sprintf( __( '%s successfully added to the whitelist.', 'advanced-ip-blocker' ), $ip ) ] ); } else { /* translators: %s: The IP address that is already whitelisted. */ wp_send_json_success( [ 'message' => sprintf( __( '%s is already whitelisted.', 'advanced-ip-blocker' ), $ip ) ] ); } } /** * AJAX callback para verificar una API key de geolocalización. */ public function ajax_verify_api_key() { if ( ! current_user_can('manage_options') ) { 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($_POST['provider']) : ''; $api_key = isset($_POST['api_key']) ? sanitize_text_field($_POST['api_key']) : ''; if (empty($provider)) { // La clave puede estar vacía para algunos proveedores wp_send_json_error( ['message' => __('Provider is missing.', 'advanced-ip-blocker')] ); } $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 { // La clave está aquí: usamos el error_message que nos devuelve el geolocation_manager. $error_message = $result['error_message'] ?? __('Invalid API Key or connection error.', 'advanced-ip-blocker'); wp_send_json_error(['message' => $error_message]); } } /** * Callback de AJAX para gestionar la respuesta al aviso de telemetría. */ public function ajax_handle_telemetry_notice() { if (!current_user_can('manage_options')) { wp_send_json_error(); } check_ajax_referer('advaipbl_telemetry_nonce', 'nonce'); $action = isset($_POST['telemetry_action']) ? sanitize_key($_POST['telemetry_action']) : ''; if ('allow' === $action) { // Obtenemos las opciones a través de la instancia del plugin. $options = $this->plugin->options; $options['allow_telemetry'] = '1'; // Usamos la constante correcta. 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'); // Usamos la referencia correcta a log_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 para generar un nuevo secreto 2FA para un usuario. */ 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 para verificar y activar 2FA para un usuario. */ 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( $_POST['code'] ) : ''; $backup_codes = isset( $_POST['backup_codes'] ) && is_array( $_POST['backup_codes'] ) ? array_map( 'sanitize_text_field', $_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 para desactivar 2FA para un usuario. */ 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 para iniciar la descarga de la base de datos GeoIP. */ 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 ); } // Aumentamos el límite de tiempo de ejecución para la descarga set_time_limit(300); $result = $this->plugin->geoip_manager->download_and_unpack_databases(); if ( $result['success'] ) { wp_send_json_success( ['message' => $result['message']] ); } else { wp_send_json_error( ['message' => $result['message']] ); } } }