Plugin Directory

Changeset 3395179


Ignore:
Timestamp:
11/13/2025 04:14:53 PM (4 months ago)
Author:
pulsechat
Message:

Release version 2.2.3 - Fixed domain normalization for license validation

Location:
pulse-chat-ai
Files:
23 added
4 edited

Legend:

Unmodified
Added
Removed
  • pulse-chat-ai/trunk/includes/class-asset-loader.php

    r3392240 r3395179  
    9797            if (isset($entry_data['imports']) && is_array($entry_data['imports'])) {
    9898                foreach ($entry_data['imports'] as $import_key) {
    99                     if (isset($manifest[$import_key]) && is_array($manifest[$import_key])) {
     99                    if (isset($manifest[$import_key])) {
    100100                        $import_data = $manifest[$import_key];
    101                         if (isset($import_data['css']) && is_array($import_data['css'])) {
    102                             foreach ($import_data['css'] as $css_file) {
    103                                 $css_files[] = PULSE_CHAT_AI_PLUGIN_URL . 'dist/' . $css_file;
     101                        // Handle both array and string formats
     102                        if (is_array($import_data)) {
     103                            if (isset($import_data['css']) && is_array($import_data['css'])) {
     104                                foreach ($import_data['css'] as $css_file) {
     105                                    $css_files[] = PULSE_CHAT_AI_PLUGIN_URL . 'dist/' . $css_file;
     106                                }
    104107                            }
     108                        } else if (is_string($import_data) && strpos($import_data, '.css') !== false) {
     109                            // Direct CSS file reference
     110                            $css_files[] = PULSE_CHAT_AI_PLUGIN_URL . 'dist/' . $import_data;
    105111                        }
    106112                    }
    107113                }
    108114            }
     115        }
     116       
     117        // Also check for globals CSS file directly
     118        $globals_css = PULSE_CHAT_AI_PLUGIN_URL . 'dist/assets/globals.css';
     119        if (file_exists(PULSE_CHAT_AI_PLUGIN_PATH . 'dist/assets/globals.css')) {
     120            $css_files[] = $globals_css;
    109121        }
    110122       
  • pulse-chat-ai/trunk/includes/class-license-manager.php

    r3394690 r3395179  
    1515    private $api_url = 'https://uhnaedqfygrqdptjngqb.supabase.co/functions/v1/license-check';
    1616   
    17     // Product slug (must match the one used in admin)
     17    // Product slug (must match EXACTLY the one used in admin/license creation)
     18    // IMPORTANT: This must be identical character-by-character in both systems
     19    // Changing this will cause 'product_mismatch' errors for all licenses
    1820    private $product_slug = 'pulse-chat-ai';
    1921   
     
    7880        }
    7981       
    80         // Get current domain
     82        // Get current domain normalized
    8183        $domain = $this->get_current_domain();
     84       
     85        // Normalize license key: convert to uppercase, trim, but keep format (with dashes)
     86        $license_key_normalized = strtoupper(trim($license_key));
    8287       
    8388        // Build URL with query parameters
    8489        $url = add_query_arg(array(
    85             'license' => $license_key,
     90            'license' => $license_key_normalized,
    8691            'domain' => $domain,
    8792            'product' => $this->product_slug
    8893        ), $this->api_url);
     94       
     95        // Debug logging
     96        if (defined('WP_DEBUG') && WP_DEBUG) {
     97            error_log('=== Validación de Licencia ===');
     98            error_log('License Key: ' . $license_key_normalized);
     99            error_log('Product Slug: ' . $this->product_slug);
     100            error_log('Site URL (raw): ' . home_url());
     101            error_log('Domain (normalized): ' . $domain);
     102            error_log('API URL: ' . $url);
     103        }
    89104       
    90105        // Make request
     
    96111        // Check for connection errors
    97112        if (is_wp_error($response)) {
     113            $error_message = $response->get_error_message();
     114            if (defined('WP_DEBUG') && WP_DEBUG) {
     115                error_log('Error de conexión con API de licencias: ' . $error_message);
     116            }
    98117            return array(
    99118                'valid' => false,
    100119                'reason' => 'connection_error',
    101120                'plan' => null,
    102                 'error' => $response->get_error_message()
     121                'error' => $error_message
    103122            );
    104123        }
     
    108127        $data = json_decode($body, true);
    109128       
    110         // Handle HTTP errors
     129        // Debug logging
     130        if (defined('WP_DEBUG') && WP_DEBUG) {
     131            error_log('Response Status Code: ' . $status_code);
     132            error_log('Response Body: ' . $body);
     133            error_log('Response Data: ' . print_r($data, true));
     134        }
     135       
     136        // Handle invalid JSON response
     137        if (!$data || !is_array($data)) {
     138            if (defined('WP_DEBUG') && WP_DEBUG) {
     139                error_log('Error al parsear respuesta de API: ' . $body);
     140            }
     141            return array(
     142                'valid' => false,
     143                'reason' => 'invalid_response',
     144                'plan' => null,
     145                'error' => 'Invalid response from server'
     146            );
     147        }
     148       
     149        // Handle HTTP errors (non-200 status codes)
    111150        if ($status_code !== 200) {
     151            // Check if it's a Supabase function not found error
     152            if ($status_code === 404 && isset($data['code']) && $data['code'] === 'NOT_FOUND') {
     153                if (defined('WP_DEBUG') && WP_DEBUG) {
     154                    error_log('ERROR: La función Edge de Supabase no está desplegada. Mensaje: ' . (isset($data['message']) ? $data['message'] : 'Function not found'));
     155                }
     156                return array(
     157                    'valid' => false,
     158                    'reason' => 'function_not_found',
     159                    'plan' => null,
     160                    'error' => 'La función de validación de licencias no está disponible. Por favor, contacta con soporte o verifica que la Edge Function esté desplegada en Supabase.'
     161                );
     162            }
     163           
    112164            $reason = 'server_error';
    113165            if (isset($data['reason'])) {
    114166                $reason = $data['reason'];
    115             }
     167            } else if ($status_code === 404) {
     168                $reason = 'not_found';
     169            }
     170           
     171            if (defined('WP_DEBUG') && WP_DEBUG) {
     172                error_log('Licencia inválida. Razón: ' . $reason);
     173            }
     174           
    116175            return array(
    117176                'valid' => false,
    118177                'reason' => $reason,
    119                 'plan' => null,
     178                'plan' => isset($data['plan']) ? $data['plan'] : null,
    120179                'error' => isset($data['message']) ? $data['message'] : 'Server error'
    121180            );
    122181        }
    123182       
    124         // Save license data if valid
    125         if (isset($data['valid']) && $data['valid'] && isset($data['plan'])) {
     183        // Verify if license is valid: check reason === 'ok' and valid === true
     184        if (isset($data['valid']) && $data['valid'] === true && isset($data['reason']) && $data['reason'] === 'ok') {
     185            // License is valid - save license data
    126186            update_option($this->license_data_option, $data);
     187           
     188            // Cache result for 24 hours
     189            set_transient('pulse_chat_ai_license_check', $data, DAY_IN_SECONDS);
     190           
     191            return $data;
    127192        } else {
     193            // License is invalid - get reason from response
     194            $reason = isset($data['reason']) ? $data['reason'] : 'server_error';
     195           
     196            if (defined('WP_DEBUG') && WP_DEBUG) {
     197                error_log('Licencia inválida. Razón: ' . $reason);
     198            }
     199           
    128200            // Clear license data if invalid
    129201            delete_option($this->license_data_option);
    130         }
    131        
    132         // Cache result for 24 hours
    133         set_transient('pulse_chat_ai_license_check', $data, DAY_IN_SECONDS);
    134        
    135         return $data;
     202           
     203            // Return error response
     204            return array(
     205                'valid' => false,
     206                'reason' => $reason,
     207                'plan' => isset($data['plan']) ? $data['plan'] : null,
     208                'error' => isset($data['message']) ? $data['message'] : 'License validation failed'
     209            );
     210        }
     211    }
     212   
     213    /**
     214     * Normalize domain according to API guide
     215     *
     216     * @param string $domain_or_url Domain or full URL to normalize
     217     * @return string Normalized domain
     218     */
     219    private function normalize_domain($domain_or_url) {
     220        // 1. Eliminar protocolo (http://, https://)
     221        $domain = preg_replace('#^https?://#', '', $domain_or_url);
     222       
     223        // 2. Eliminar rutas y parámetros (todo después de /)
     224        $domain = preg_replace('#/.*$#', '', $domain);
     225       
     226        // 3. Eliminar www. al inicio
     227        $domain = preg_replace('#^www\.#', '', $domain);
     228       
     229        // 4. Convertir a minúsculas
     230        $domain = strtolower($domain);
     231       
     232        // 5. Eliminar espacios y trim
     233        $domain = trim($domain);
     234       
     235        // 6. IMPORTANTE: Eliminar puerto si existe (sin excepciones, ya que no validamos localhost)
     236        // Ejemplo: "ejemplo.com:443" -> "ejemplo.com"
     237        // Ejemplo: "ejemplo.com:8080" -> "ejemplo.com"
     238        // Ejemplo: "localhost:8881" -> "localhost"
     239        if (strpos($domain, ':') !== false) {
     240            $domain = explode(':', $domain)[0];
     241        }
     242       
     243        return $domain;
    136244    }
    137245   
     
    140248     */
    141249    private function get_current_domain() {
    142         $domain = isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '';
    143        
    144         // Remove www and protocol if exists
    145         $domain = preg_replace('/^www\./', '', $domain);
    146        
    147         // Remove port if exists
    148         $domain = preg_replace('/:\d+$/', '', $domain);
    149        
    150         return strtolower(trim($domain));
     250        // Use home_url() as recommended in the guide
     251        $site_url = home_url();
     252        return $this->normalize_domain($site_url);
    151253    }
    152254   
     
    207309    public function get_error_message($reason) {
    208310        $messages = array(
     311            'ok' => __('License is valid.', 'pulse-chat-ai'),
    209312            'no_license' => __('No active license. Please enter your license key.', 'pulse-chat-ai'),
    210313            'not_found' => __('License not found. Please verify that the key is correct.', 'pulse-chat-ai'),
     
    213316            'domain_mismatch' => __('This license is not valid for this domain.', 'pulse-chat-ai'),
    214317            'product_mismatch' => __('This license is not for this product.', 'pulse-chat-ai'),
     318            'missing_params' => __('Missing required parameters.', 'pulse-chat-ai'),
    215319            'connection_error' => __('Connection error. Please check your internet connection.', 'pulse-chat-ai'),
    216             'server_error' => __('Server error. Please try again later.', 'pulse-chat-ai')
     320            'server_error' => __('Server error. Please try again later.', 'pulse-chat-ai'),
     321            'invalid_response' => __('Invalid response from server.', 'pulse-chat-ai'),
     322            'function_not_found' => __('The license validation function is not available. Please contact support or verify that the Supabase Edge Function is deployed.', 'pulse-chat-ai')
    217323        );
    218324       
  • pulse-chat-ai/trunk/pulse-chat-ai.php

    r3394690 r3395179  
    44 * Plugin URI: https://pulsechatai.com
    55 * Description: AI-powered ChatGPT 5 chat assistant for WordPress. Perfect for customer support and engagement.
    6  * Version: 2.2.0
     6 * Version: 2.2.3
    77 * Requires at least: 5.0
    88 * Requires PHP: 7.4
     
    2222
    2323// Define plugin constants
    24 define('PULSE_CHAT_AI_VERSION', '2.2.0');
     24define('PULSE_CHAT_AI_VERSION', '2.2.3');
    2525define('PULSE_CHAT_AI_PLUGIN_URL', plugin_dir_url(__FILE__));
    2626define('PULSE_CHAT_AI_PLUGIN_PATH', plugin_dir_path(__FILE__));
  • pulse-chat-ai/trunk/readme.txt

    r3394690 r3395179  
    66Tested up to: 6.8
    77Requires PHP: 7.4
    8 Stable tag: 2.2.0
     8Stable tag: 2.2.3
    99License: GPLv2 or later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    127127
    128128== Changelog ==
     129
     130= 2.2.3 - January 2026 =
     131* FIXED: Domain normalization now always removes ports (no localhost exception)
     132* FIXED: License validation domain mismatch issues resolved
     133* IMPROVED: Domain normalization aligned with Supabase license system
     134* IMPROVED: Added important comments about product_slug matching requirements
    129135
    130136= 2.2.0 - January 2026 =
Note: See TracChangeset for help on using the changeset viewer.