Plugin Directory

Changeset 3496550


Ignore:
Timestamp:
04/01/2026 12:44:48 PM (38 hours ago)
Author:
boxedchat
Message:

Updated plugin to version 1.2.3

Location:
boxedchat-chat-widget/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • boxedchat-chat-widget/trunk/README.txt

    r3496494 r3496550  
    1 === BoxedChat – AI Chat Widget & Support ===
     1=== BoxedChat – AI Chat Widget & Support & Helpdesk ===
    22Contributors: boxedchat
    33Tags: boxedchat, widget, integration, support, live chat
     
    1414
    1515BoxedChat Integration is a lightweight WordPress plugin that allows you to embed BoxedChat workspace widgets directly on your WordPress site. With just one click, users are securely redirected to BoxedChat to authenticate and select a workspace - no passwords needed in WordPress!
    16 **Official website:** [https://boxed.chat/](https://boxed.chat/)
    1716
    1817**Features:**
     
    2524- Works with all BoxedChat workspaces
    2625
    27 
    2826== Installation ==
    2927
    30 2. Download and activate the plugin through the 'Plugins' menu in WordPress.
    31 3. Go to Boxedchat Tab in Side Menu.
    32 4. Click "Connect to BoxedChat" and follow the OAuth flow.
     281. Upload the `workspace-widget` folder to `/wp-content/plugins/`
     292. Activate the plugin through the 'Plugins' menu in WordPress
     303. Go to Settings > Workspace Widget to connect your BoxedChat account
     314. Click "Connect to BoxedChat" and follow the OAuth flow
    33325. Select a workspace to embed on your site
    34 6. Done! The widget automatically appears on all pages.
     336. Done! The widget automatically appears on all pages
    3534
    3635== Usage ==
     
    5453== Configuration ==
    5554
    56 1. Navigate to BoxedChat in your WordPress admin panel
     551. Navigate to Settings > BoxedChat Integration in your WordPress admin panel
    57562. Click "Connect to BoxedChat"
    58573. Login to your BoxedChat account
    59584. Select the workspace you want to embed
    60 5. Click "Save Changes"
     595. Set the widget height (optional, default is 600px)
     606. Click "Save Changes"
    6161
    6262== Frequently Asked Questions ==
     
    6666
    6767**Q: Can I embed multiple widgets?**
    68 A: The plugin embeds one workspace widget by default.
     68A: The plugin embeds one workspace widget by default. Use the shortcode `[workspace_widget]` to add additional instances.
     69
     70**Q: Does the widget work with WordPress multisite?**
     71A: Yes, the plugin works with WordPress multisite installations. Each site can connect to a different BoxedChat workspace.
    6972
    7073**Q: Can I change which workspace is embedded?**
    71 A: Yes, click "Disconnect & Reconnect" in BoxedChat to select a different workspace.
     74A: Yes, click "Disconnect & Reconnect" in Settings > BoxedChat Integration to select a different workspace.
    7275
    7376**Q: How do I remove the widget?**
     
    7679== Changelog ==
    7780
    78 = 1.2.2 =
     81= 1.2.3 =
    7982- Improved security with API key management
    8083
    81 = 1.2.1 =
     84= 1.1.0 =
    8285- Switched to OAuth authentication flow
    8386- Auto-embedding of widget on all pages
     
    8588- Improved security with API key management
    8689
    87 = 1.1.0 =
     90= 1.0.0 =
    8891- Initial release
  • boxedchat-chat-widget/trunk/boxedchat-chat-widget.php

    r3496494 r3496550  
    11<?php
    22/**
    3  * Plugin Name: BoxedChat – AI Chat Widget & Support
     3 * Plugin Name: BoxedChat – AI Chat Widget & Support & Helpdesk
    44 * Description: Add a free live chat widget to your website in minutes. Talk to visitors, capture leads, and support customers with Boxed.chat.
    5  * Version: 1.2.2
     5 * Version: 1.2.3
    66 * Author: boxedchat
    77 * Author URI: https://boxed.chat
     
    1212 */
    1313
    14 
    1514if (!defined('ABSPATH')) exit;
    1615
     
    1817add_action('admin_init', function() {
    1918  if (!isset($_POST['boxchat_nonce'])) return;
    20 
    2119  if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['boxchat_nonce'])), 'boxchat_settings')) return;
    22 
    2320  if (!current_user_can('manage_options')) {
    24     wp_die(esc_html__('You do not have permission.', 'boxedchat-chat-widget'), 403);
     21    wp_die(esc_html__('You do not have permission to perform this action.', 'boxedchat-chat-widget'), 403);
    2522  }
    2623
    2724  if (isset($_POST['connect_boxchat'])) {
    28 
    29     $callback_nonce = wp_create_nonce('boxchat_wp_callback');
    30 
    31     $wordpress_url = admin_url('admin.php?page=boxchat-settings');
    32 
    33 $wordpress_url = admin_url('admin.php?page=boxchat-settings');
    34 $site_host = wp_parse_url(get_site_url(), PHP_URL_HOST);
    35 
    36 $auth_url = add_query_arg(array(
    37   'wordpressUrl'   => $wordpress_url,
    38   'siteId'         => $site_host,
    39   'callbackNonce'  => $callback_nonce,
    40   'boxchat_callback' => '1',
    41 ), 'https://boxed.chat/auth/wp-plugin');
    42 
    43     wp_safe_redirect($auth_url);
     25    $site_url        = get_site_url();
     26    $site_host       = wp_parse_url($site_url, PHP_URL_HOST);
     27    $boxchat_app_url = 'https://boxed.chat';
     28
     29    // Generate a nonce and store it server-side in a transient so the callback
     30    // can verify it without relying on the external OAuth provider to carry URL
     31    // parameters back (BoxedChat constructs its own redirect and does not
     32    // preserve custom query params).
     33    $callback_nonce = wp_create_nonce('boxedchat_oauth_callback');
     34    $user_id        = get_current_user_id();
     35    set_transient('boxchat_pending_auth_' . $user_id, $callback_nonce, 10 * MINUTE_IN_SECONDS);
     36
     37    // wordpressUrl must be the WP admin settings page so BoxedChat redirects
     38    // the admin back there (with apiKey, domain, etc. appended) after auth.
     39    $admin_return_url = add_query_arg(
     40      array('page' => 'boxchat-settings'),
     41      admin_url('admin.php')
     42    );
     43
     44    $auth_url = add_query_arg(array(
     45      'wordpressUrl'     => $admin_return_url,
     46      'siteId'           => $site_host,
     47      'boxchat_callback' => '1',
     48    ), $boxchat_app_url . '/auth/wp-plugin');
     49
     50    add_filter('allowed_redirect_hosts', function( $hosts ) {
     51      $hosts[] = 'boxed.chat';
     52      return $hosts;
     53    });
     54
     55    wp_safe_redirect(esc_url_raw($auth_url), 302, 'BoxedChat');
    4456    exit;
    4557  }
     
    5163    delete_option('boxchat_workspace_name');
    5264    delete_option('boxchat_api_key');
     65    delete_option('boxchat_connection_token');
    5366
    5467    wp_safe_redirect(admin_url('admin.php?page=boxchat-settings'));
     
    7588  $workspace_id   = get_option('boxchat_workspace_id');
    7689  $workspace_name = get_option('boxchat_workspace_name');
    77 if (
    78   isset($_GET['boxchat_callback'], $_GET['apiKey'], $_GET['callbackNonce'])
    79 ) {
    80 
    81   // ✅ Permission check
    82   if (!current_user_can('manage_options')) {
    83     wp_die(
    84       esc_html__('You do not have permission to perform this action.', 'boxedchat-chat-widget'),
    85       403
    86     );
    87   }
    88 
    89   // ✅ REAL nonce verification (from request)
    90   $nonce = sanitize_text_field(wp_unslash($_GET['callbackNonce']));
    91 
    92   if (!wp_verify_nonce($nonce, 'boxchat_wp_callback')) {
    93     wp_die(
    94       esc_html__('Security check failed. Please reconnect.', 'boxedchat-chat-widget'),
    95       403
    96     );
    97   }
    98 
    99   // ✅ Store data safely
    100   $received_api_key = sanitize_text_field(wp_unslash($_GET['apiKey']));
    101   update_option('boxchat_api_key', $received_api_key);
    102   update_option('boxchat_is_connected', true);
    103 
    104   if (isset($_GET['domain'])) {
    105     update_option('boxchat_domain', sanitize_text_field(wp_unslash($_GET['domain'])));
    106   }
    107 
    108   if (isset($_GET['workspaceId'])) {
    109     update_option('boxchat_workspace_id', sanitize_text_field(wp_unslash($_GET['workspaceId'])));
    110   }
    111 
    112   if (isset($_GET['workspaceName'])) {
    113     update_option('boxchat_workspace_name', sanitize_text_field(wp_unslash($_GET['workspaceName'])));
    114   }
    115 
    116   echo '<div class="notice notice-success is-dismissible"><p>' .
    117     esc_html__('Successfully connected to BoxedChat!', 'boxedchat-chat-widget') .
    118   '</p></div>';
    119 }
     90  // -----------------------------------------------------------------------
     91  // Handle GET callback: BoxedChat redirects the admin back here after auth.
     92  //
     93  // Security is applied strictly in order — no conditions are combined so
     94  // no check can be bypassed:
     95  //   1. Nonce verification  — the nonce created at Connect time is stored in
     96  //                            a transient (server-side) because BoxedChat
     97  //                            constructs its own redirect URL and does not
     98  //                            carry custom GET params back. The transient is
     99  //                            retrieved and verified with wp_verify_nonce
     100  //                            before any input is touched.
     101  //   2. Capability check    — confirms only admins may write plugin options.
     102  //   3. Input processing    — sanitize and store ONLY after both checks pass.
     103  // -----------------------------------------------------------------------
     104  if (isset($_GET['boxchat_callback']) && isset($_GET['apiKey'])) {
     105
     106    // 1. Nonce verification — retrieve the nonce stored at Connect time.
     107    $user_id      = get_current_user_id();
     108    $stored_nonce = get_transient('boxchat_pending_auth_' . $user_id);
     109
     110    if (!$stored_nonce) {
     111      return;
     112    }
     113    if (!wp_verify_nonce($stored_nonce, 'boxedchat_oauth_callback')) {
     114      return;
     115    }
     116
     117    // Consume the transient immediately so the callback URL cannot be replayed.
     118    delete_transient('boxchat_pending_auth_' . $user_id);
     119
     120    // 2. Permission check — verified separately, after nonce, never combined.
     121    if (!current_user_can('manage_options')) {
     122      return;
     123    }
     124
     125    // 3. Process input ONLY after both checks above have passed.
     126    $received_api_key = sanitize_text_field(wp_unslash($_GET['apiKey']));
     127    update_option('boxchat_api_key', $received_api_key);
     128    update_option('boxchat_is_connected', true);
     129
     130    if (isset($_GET['domain'])) {
     131      $domain = sanitize_text_field(wp_unslash($_GET['domain']));
     132      update_option('boxchat_domain', $domain);
     133    }
     134
     135    if (isset($_GET['workspaceId'])) {
     136      $workspace_id = sanitize_text_field(wp_unslash($_GET['workspaceId']));
     137      update_option('boxchat_workspace_id', $workspace_id);
     138    }
     139
     140    if (isset($_GET['workspaceName'])) {
     141      $workspace_name = sanitize_text_field(wp_unslash($_GET['workspaceName']));
     142      update_option('boxchat_workspace_name', $workspace_name);
     143    }
     144
     145    echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__('Successfully connected to BoxedChat!', 'boxedchat-chat-widget') . '</p></div>';
     146  }
    120147  ?>
    121148  <div class="wrap">
Note: See TracChangeset for help on using the changeset viewer.