Plugin Directory

Changeset 3463219


Ignore:
Timestamp:
02/17/2026 08:42:15 AM (6 weeks ago)
Author:
quantumcloud
Message:

Improved security

Location:
chatbot
Files:
388 added
4 edited

Legend:

Unmodified
Added
Removed
  • chatbot/trunk/js/qcld-wp-chatbot-plugin.js

    r3444025 r3463219  
    22392239                    var page = obj.attr('data-page');
    22402240                    obj.text('Loading...');
    2241                     var data = {'action':'wpbo_search_site_pagination','name':globalwpw.hasNameCookie,'keyword':keyword,'language': globalwpw.settings.obj.language,'type': post_type, 'page': page};
     2241                    var data = {'action':'wpbo_search_site_pagination','name':globalwpw.hasNameCookie,'keyword':keyword,'language': globalwpw.settings.obj.language,'type': post_type, 'page': page, 'nonce': qcld_chatbot_obj.nonce};
    22422242                    if($(globalwpw.settings.messageLastChild+' .wp-chatbot-comment-loader').length==0){
    22432243                        $(globalwpw.settings.messageContainer).append(wpwKits.botPreloader());
  • chatbot/trunk/qcld-wpwbot-search.php

    r3391642 r3463219  
    321321    global $wpdb;
    322322
    323     $keyword           = sanitize_text_field( $_POST['keyword'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
    324     $post_type         = sanitize_text_field( $_POST['type'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
    325     $page              = sanitize_text_field( $_POST['page'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
     323    // Verify nonce for security
     324    if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'wpbot_search_nonce' ) ) {
     325        wp_send_json_error( array( 'message' => 'Security check failed' ) );
     326        wp_die();
     327    }
     328
     329    // Sanitize and validate inputs
     330    $keyword           = isset( $_POST['keyword'] ) ? sanitize_text_field( $_POST['keyword'] ) : '';
     331    $post_type         = isset( $_POST['type'] ) ? sanitize_text_field( $_POST['type'] ) : 'post';
     332    $page              = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 0;
     333   
     334    // Validate post type against allowed types
     335    $allowed_post_types = array( 'post', 'page', 'product' );
     336    if ( ! in_array( $post_type, $allowed_post_types, true ) ) {
     337        $post_type = 'post';
     338    }
     339
    326340    $enable_post_types = get_option( 'wppt_post_types' );
    327341    $load_more         = maybe_unserialize( get_option( 'qlcd_wp_chatbot_load_more' ) );
     
    333347        $load_more = $load_more[ array_rand( $load_more ) ];
    334348    }
    335     $searchlimit = ( get_option( 'wppt_number_of_result' ) == '' ? '5' : get_option( 'wppt_number_of_result' ) );
     349    $searchlimit = ( get_option( 'wppt_number_of_result' ) == '' ? 5 : absint( get_option( 'wppt_number_of_result' ) ) );
    336350    $orderby     = ( get_option( 'wppt_result_orderby' ) == '' ? 'none' : get_option( 'wppt_result_orderby' ) );
    337351    $order       = ( get_option( 'wppt_result_order' ) == '' ? 'ASC' : get_option( 'wppt_result_order' ) );
     
    340354    $new_window = get_option( 'wpbot_search_result_new_window' );
    341355
    342     $total_items = get_option( 'wppt_number_of_result' );
     356    $total_items = absint( get_option( 'wppt_number_of_result' ) );
     357    if ( $total_items < 1 ) {
     358        $total_items = 5;
     359    }
    343360
    344361    $searchkeyword = qcld_wpbot_modified_keyword( $keyword );
     
    348365    $response['html']   = '';
    349366
    350     // $sql = "SELECT * FROM ". $wpdb->prefix."posts where post_type in ('".$post_type."') and post_status='publish' and ((post_title REGEXP '\\b".$searchkeyword."\\b'))";
     367    // Use prepared statements to prevent SQL injection
    351368    if ( get_option( 'active_advance_query' ) != '1' ) {
    352         $sql   = 'SELECT * FROM ' . $wpdb->prefix . "posts where post_type in ('" . $post_type . "') and post_status='publish' and ((post_title LIKE '%" . $searchkeyword . "%')) order by ID DESC";
    353         $limit = ' Limit 0, ' . $searchlimit;
     369        // Simple query - search in post_title only
     370        $sql = $wpdb->prepare(
     371            "SELECT * FROM {$wpdb->prefix}posts
     372            WHERE post_type = %s
     373            AND post_status = 'publish'
     374            AND post_title LIKE %s
     375            ORDER BY ID DESC",
     376            $post_type,
     377            '%' . $wpdb->esc_like( $searchkeyword ) . '%'
     378        );
    354379    } else {
    355         // advance query building
    356         $sql   = 'SELECT * FROM ' . $wpdb->prefix . "posts where post_type in ('" . $post_type . "') and post_status='publish' and ((post_title REGEXP '\\b" . $searchkeyword . "\\b') or (post_content REGEXP '\\b" . $searchkeyword . "\\b')) order by ID DESC";
    357         $limit = ' Limit 0, ' . $searchlimit;
    358     }
     380        // Advanced query - search in both post_title and post_content
     381        $sql = $wpdb->prepare(
     382            "SELECT * FROM {$wpdb->prefix}posts
     383            WHERE post_type = %s
     384            AND post_status = 'publish'
     385            AND (post_title REGEXP %s OR post_content REGEXP %s)
     386            ORDER BY ID DESC",
     387            $post_type,
     388            '[[:<:]]' . $searchkeyword . '[[:>:]]',
     389            '[[:<:]]' . $searchkeyword . '[[:>:]]'
     390        );
     391    }
     392   
    359393    $total_results = $wpdb->get_results( $sql );
    360394
    361395    if ( ! empty( $total_results ) ) {
     396
     397        // Validate and sanitize orderby parameter
     398        $valid_orderby = array( 'title', 'date', 'modified', 'none', 'rand' );
     399        if ( ! in_array( $orderby, $valid_orderby, true ) ) {
     400            $orderby = 'none';
     401        }
    362402
    363403        if ( $orderby == 'title' ) {
     
    371411        }
    372412
    373         if ( $orderby != 'none' or $orderby != 'rand' ) {
    374             $sql .= " order by $orderby $order";
    375         }
    376         $limit = ' Limit ' . ( $total_items * $page ) . ", $total_items";
    377 
    378         $results = $wpdb->get_results( $sql . $limit );
     413        // Validate order parameter
     414        $order = strtoupper( $order );
     415        if ( ! in_array( $order, array( 'ASC', 'DESC' ), true ) ) {
     416            $order = 'ASC';
     417        }
     418
     419        // Build query with pagination
     420        $offset = absint( $total_items * $page );
     421       
     422        if ( get_option( 'active_advance_query' ) != '1' ) {
     423            if ( $orderby != 'none' && $orderby != 'rand' ) {
     424                $sql = $wpdb->prepare(
     425                    "SELECT * FROM {$wpdb->prefix}posts
     426                    WHERE post_type = %s
     427                    AND post_status = 'publish'
     428                    AND post_title LIKE %s
     429                    ORDER BY {$orderby} {$order}
     430                    LIMIT %d, %d",
     431                    $post_type,
     432                    '%' . $wpdb->esc_like( $searchkeyword ) . '%',
     433                    $offset,
     434                    $total_items
     435                );
     436            } else {
     437                $sql = $wpdb->prepare(
     438                    "SELECT * FROM {$wpdb->prefix}posts
     439                    WHERE post_type = %s
     440                    AND post_status = 'publish'
     441                    AND post_title LIKE %s
     442                    ORDER BY ID DESC
     443                    LIMIT %d, %d",
     444                    $post_type,
     445                    '%' . $wpdb->esc_like( $searchkeyword ) . '%',
     446                    $offset,
     447                    $total_items
     448                );
     449            }
     450        } else {
     451            if ( $orderby != 'none' && $orderby != 'rand' ) {
     452                $sql = $wpdb->prepare(
     453                    "SELECT * FROM {$wpdb->prefix}posts
     454                    WHERE post_type = %s
     455                    AND post_status = 'publish'
     456                    AND (post_title REGEXP %s OR post_content REGEXP %s)
     457                    ORDER BY {$orderby} {$order}
     458                    LIMIT %d, %d",
     459                    $post_type,
     460                    '[[:<:]]' . $searchkeyword . '[[:>:]]',
     461                    '[[:<:]]' . $searchkeyword . '[[:>:]]',
     462                    $offset,
     463                    $total_items
     464                );
     465            } else {
     466                $sql = $wpdb->prepare(
     467                    "SELECT * FROM {$wpdb->prefix}posts
     468                    WHERE post_type = %s
     469                    AND post_status = 'publish'
     470                    AND (post_title REGEXP %s OR post_content REGEXP %s)
     471                    ORDER BY ID DESC
     472                    LIMIT %d, %d",
     473                    $post_type,
     474                    '[[:<:]]' . $searchkeyword . '[[:>:]]',
     475                    '[[:<:]]' . $searchkeyword . '[[:>:]]',
     476                    $offset,
     477                    $total_items
     478                );
     479            }
     480        }
     481
     482        $results = $wpdb->get_results( $sql );
    379483    } else {
    380484        if ( class_exists( 'SitePress' ) ) {
    381485            global $sitepress;
    382             $selected_lan = sanitize_text_field( $_POST['language'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
     486            $selected_lan = isset( $_POST['language'] ) ? sanitize_text_field( $_POST['language'] ) : '';
    383487            $selected_lan = explode( '_', $selected_lan );
    384             $sitepress->switch_lang( $selected_lan[0], true );
    385 
    386         }
     488            if ( ! empty( $selected_lan[0] ) ) {
     489                $sitepress->switch_lang( $selected_lan[0], true );
     490            }
     491        }
     492       
    387493        $query_arg = array(
    388494            'post_type'      => $post_type,
     
    393499            'orderby'        => $orderby,
    394500        );
     501       
    395502        if ( class_exists( 'SitePress' ) ) {
    396503            global $sitepress;
    397             $selected_lan = sanitize_text_field( $_POST['language'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
     504            $selected_lan = isset( $_POST['language'] ) ? sanitize_text_field( $_POST['language'] ) : '';
    398505            $selected_lan = explode( '_', $selected_lan );
    399             $sitepress->switch_lang( $selected_lan[0], true );
    400 
     506            if ( ! empty( $selected_lan[0] ) ) {
     507                $sitepress->switch_lang( $selected_lan[0], true );
     508            }
    401509        }
    402510
    403511        $query_arg['suppress_filters'] = true;
    404         if ( $orderby != 'none' or $orderby != 'rand' ) {
     512        if ( $orderby != 'none' && $orderby != 'rand' ) {
    405513            $query_arg['order'] = $order;
    406514        }
     
    411519                'post_status' => 'publish',
    412520                's'           => stripslashes( $keyword ),
    413 
    414521            )
    415522        );
     
    420527    }
    421528
    422 
    423 
    424 
    425 
    426529    if ( ! empty( $total_results ) ) {
    427530
    428         $selected_lan     = sanitize_text_field( $_POST['language'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
     531        $selected_lan     = isset( $_POST['language'] ) ? sanitize_text_field( $_POST['language'] ) : '';
    429532        $urlss            = get_option( 'wpbotml_url_urls' ) ? get_option( 'wpbotml_url_urls' ) : '';
    430533        $imagesize        = ( get_option( 'wpbot_search_image_size' ) != '' ? get_option( 'wpbot_search_image_size' ) : 'thumbnail' );
    431534
    432 
    433535        $response['html'] .= '<div class="wpb-search-result">';
    434536
    435                 foreach ( $total_results as $result ) {
    436 
    437                     if ( $result->post_type == 'product' ) {
    438                         if ( ! class_exists( 'WooCommerce' ) ) {
    439                             continue;
    440                         }
     537        foreach ( $total_results as $result ) {
     538
     539            if ( $result->post_type == 'product' ) {
     540                if ( ! class_exists( 'WooCommerce' ) ) {
     541                    continue;
     542                }
     543            }
     544
     545            $featured_img_url = get_the_post_thumbnail_url( $result->ID, $thumb );
     546            $excerpt = '';
     547            if ( isset( $result->ID ) ) {
     548                $post_obj = get_post( $result->ID );
     549                if ( $post_obj ) {
     550                    if ( has_excerpt( $result->ID ) ) {
     551                        $excerpt = get_the_excerpt( $result->ID );
     552                    } else {
     553                        $content = $post_obj->post_content;
     554
     555                        // Remove ALL WPBakery shortcodes (paired + self-closing)
     556                        $content = preg_replace( '/\[vc_[^\]]*\](.*?)\[\/vc_[^\]]*\]/s', '$1', $content ); // paired
     557                        $content = preg_replace( '/\[vc_[^\]]*\]/s', '', $content ); // self-closing
     558                        $content = preg_replace('/\[\/?[\w\-]+[^\]]*\]/', '', $content);
     559                        // Extra: remove any leftover [] shortcodes (just in case)
     560                        $content = strip_shortcodes( $content );
     561
     562                        // Run through normal WP content filters
     563                        $content_filtered = apply_filters( 'the_content', $content );
     564
     565                        // Strip HTML tags, then trim
     566                        $excerpt = wp_trim_words( wp_strip_all_tags( $content_filtered ), 20, '...' );
    441567                    }
    442 
    443                     $featured_img_url = get_the_post_thumbnail_url( $result->ID, $thumb );
    444                     $excerpt = '';
    445                     if ( isset( $result->ID ) ) {
    446                         $post_obj = get_post( $result->ID );
    447                         if ( $post_obj ) {
    448                             if ( has_excerpt( $result->ID ) ) {
    449                                 $excerpt = get_the_excerpt( $result->ID );
    450                             } else {
    451                                 $content = $post_obj->post_content;
    452 
    453                                 // Remove ALL WPBakery shortcodes (paired + self-closing)
    454                                 $content = preg_replace( '/\[vc_[^\]]*\](.*?)\[\/vc_[^\]]*\]/s', '$1', $content ); // paired
    455                                 $content = preg_replace( '/\[vc_[^\]]*\]/s', '', $content ); // self-closing
    456                                 $content = preg_replace('/\[\/?[\w\-]+[^\]]*\]/', '', $content);
    457                                 // Extra: remove any leftover [] shortcodes (just in case)
    458                                 $content = strip_shortcodes( $content );
    459 
    460                                 // Run through normal WP content filters
    461                                 $content_filtered = apply_filters( 'the_content', $content );
    462 
    463                                 // Strip HTML tags, then trim
    464                                 $excerpt = wp_trim_words( wp_strip_all_tags( $content_filtered ), 20, '...' );
    465                             }
    466                         }
    467                     }
    468                    
    469                    
    470                     $response['html'] .= '<div class="wpbot_card_wraper">';
    471                     $response['html'] .= '<div class="wpbot_card_image ' . ( $result->post_type == 'product' ? 'wp-chatbot-product' : '' ) . ' ' . ( $featured_img_url == '' ? 'wpbot_card_image_saas' : '' ) . '"><a href="' . esc_url( get_permalink( $result->ID ) ) . '" ' . ( $new_window == 1 ? 'target="_blank"' : '' ) . ' ' . ( $result->post_type == 'product' ? 'wp-chatbot-pid="' . $result->ID . '"' : '' ) . '>';
    472                     if ( $featured_img_url != '' ) {
    473                         $response['html'] .= '<img src="' . esc_url_raw( $featured_img_url ) . '" />';
    474                     }
    475 
    476                     $response['html'] .= '<div class="wpbot_card_caption ' . ( $featured_img_url == '' ? 'wpbot_card_caption_saas' : '' ) . '">';
    477                     $response['html'] .= '<p class="wpbot_card_caption_title"><span style="padding: 0 5px;color: #1d73b4;display: inline-block;margin: 0 5px 0 0;width: 18px;height: 18px;border-radius: 50%;font-size: 20px;line-height: 22px;"> ✓ </span> ' . esc_html( $result->post_title ) . '</p>';
    478                     $response['html'] .= '<p class="wpbot_card_description">' . esc_html( $excerpt ) . '</p>';
    479                     if ( $result->post_type == 'product' ) {
    480                         if ( class_exists( 'WooCommerce' ) ) {
    481                             $product           = wc_get_product( $result->ID );
    482                             $response['html'] .= '<p class="wpbot_product_price">' . get_woocommerce_currency_symbol() . $product->get_price_html() . '</p>';
    483                         }
    484                     }
    485                     $response['html'] .= '</div>';
    486                     $response['html'] .= '</a></div>';
    487                     $response['html'] .= '</div>';
    488                    
    489568                }
    490                
     569            }
     570           
     571           
     572            $response['html'] .= '<div class="wpbot_card_wraper">';
     573            $response['html'] .= '<div class="wpbot_card_image ' . ( $result->post_type == 'product' ? 'wp-chatbot-product' : '' ) . ' ' . ( $featured_img_url == '' ? 'wpbot_card_image_saas' : '' ) . '"><a href="' . esc_url( get_permalink( $result->ID ) ) . '" ' . ( $new_window == 1 ? 'target="_blank"' : '' ) . ' ' . ( $result->post_type == 'product' ? 'wp-chatbot-pid="' . absint( $result->ID ) . '"' : '' ) . '>';
     574            if ( $featured_img_url != '' ) {
     575                $response['html'] .= '<img src="' . esc_url_raw( $featured_img_url ) . '" />';
     576            }
     577
     578            $response['html'] .= '<div class="wpbot_card_caption ' . ( $featured_img_url == '' ? 'wpbot_card_caption_saas' : '' ) . '">';
     579            $response['html'] .= '<p class="wpbot_card_caption_title"><span style="padding: 0 5px;color: #1d73b4;display: inline-block;margin: 0 5px 0 0;width: 18px;height: 18px;border-radius: 50%;font-size: 20px;line-height: 22px;"> ✓ </span> ' . esc_html( $result->post_title ) . '</p>';
     580            $response['html'] .= '<p class="wpbot_card_description">' . esc_html( $excerpt ) . '</p>';
     581            if ( $result->post_type == 'product' ) {
     582                if ( class_exists( 'WooCommerce' ) ) {
     583                    $product           = wc_get_product( $result->ID );
     584                    $response['html'] .= '<p class="wpbot_product_price">' . get_woocommerce_currency_symbol() . $product->get_price_html() . '</p>';
     585                }
     586            }
     587            $response['html'] .= '</div>';
     588            $response['html'] .= '</a></div>';
     589            $response['html'] .= '</div>';
     590           
     591        }
     592       
    491593       
    492594        $response['html']  .= '</div>';
     
    494596
    495597    }
    496         wp_reset_query();
     598    wp_reset_query();
    497599
    498600    if ( $response['status'] != 'success' ) {
    499601        $texts            = maybe_unserialize( get_option( 'qlcd_wp_chatbot_no_result' ) );
    500         $selected_lan     = sanitize_text_field( $_POST['language'] );// phpcs:ignore WordPress.Security.NonceVerification.Missing
    501         $texts            = str_replace( "\'", "'", $texts[ $selected_lan ][0] );
    502         $response['html'] = array( $texts );
    503 
     602        $selected_lan     = isset( $_POST['language'] ) ? sanitize_text_field( $_POST['language'] ) : '';
     603        if ( ! empty( $texts ) && is_array( $texts ) && isset( $texts[ $selected_lan ][0] ) ) {
     604            $texts            = str_replace( "\'", "'", $texts[ $selected_lan ][0] );
     605            $response['html'] = array( $texts );
     606        } else {
     607            $response['html'] = array( 'No results found' );
     608        }
    504609    }
    505610    wp_send_json( $response );
  • chatbot/trunk/qcld-wpwbot.php

    r3460742 r3463219  
    55 * Description: ChatBot is a native WordPress ChatBot plugin to provide live chat support and lead generation
    66 * Donate link: https://www.wpbot.pro/
    7  * Version: 7.7.9
     7 * Version: 7.8.0
    88 * @author    QuantumCloud
    99 * Author: ChatBot for WordPress - WPBot
     
    4242
    4343if ( ! defined( 'QCLD_wpCHATBOT_VERSION' ) ) {
    44     define('QCLD_wpCHATBOT_VERSION', '7.7.9');
     44    define('QCLD_wpCHATBOT_VERSION', '7.8.0');
    4545}
    4646if ( ! defined( 'QCLD_wpCHATBOT_REQUIRED_wpCOMMERCE_VERSION' ) ) {
  • chatbot/trunk/readme.txt

    r3460742 r3463219  
    55Requires at least: 4.6
    66Tested up to: 6.9
    7 Stable tag: 7.7.9
     7Stable tag: 7.8.0
    88Requires PHP: 5.6
    99License: GPLv2 or later
     
    360360== Changelog ==
    361361
     362= 7.8.0 =
     363# Improved security
     364
    362365= 7.7.9 =
    363366# Fixed an issue with Gemini Integration
Note: See TracChangeset for help on using the changeset viewer.