Changeset 3496550
- Timestamp:
- 04/01/2026 12:44:48 PM (38 hours ago)
- Location:
- boxedchat-chat-widget/trunk
- Files:
-
- 2 edited
-
README.txt (modified) (7 diffs)
-
boxedchat-chat-widget.php (modified) (5 diffs)
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 === 2 2 Contributors: boxedchat 3 3 Tags: boxedchat, widget, integration, support, live chat … … 14 14 15 15 BoxedChat 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/)17 16 18 17 **Features:** … … 25 24 - Works with all BoxedChat workspaces 26 25 27 28 26 == Installation == 29 27 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. 28 1. Upload the `workspace-widget` folder to `/wp-content/plugins/` 29 2. Activate the plugin through the 'Plugins' menu in WordPress 30 3. Go to Settings > Workspace Widget to connect your BoxedChat account 31 4. Click "Connect to BoxedChat" and follow the OAuth flow 33 32 5. Select a workspace to embed on your site 34 6. Done! The widget automatically appears on all pages .33 6. Done! The widget automatically appears on all pages 35 34 36 35 == Usage == … … 54 53 == Configuration == 55 54 56 1. Navigate to BoxedChatin your WordPress admin panel55 1. Navigate to Settings > BoxedChat Integration in your WordPress admin panel 57 56 2. Click "Connect to BoxedChat" 58 57 3. Login to your BoxedChat account 59 58 4. Select the workspace you want to embed 60 5. Click "Save Changes" 59 5. Set the widget height (optional, default is 600px) 60 6. Click "Save Changes" 61 61 62 62 == Frequently Asked Questions == … … 66 66 67 67 **Q: Can I embed multiple widgets?** 68 A: The plugin embeds one workspace widget by default. 68 A: 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?** 71 A: Yes, the plugin works with WordPress multisite installations. Each site can connect to a different BoxedChat workspace. 69 72 70 73 **Q: Can I change which workspace is embedded?** 71 A: Yes, click "Disconnect & Reconnect" in BoxedChatto select a different workspace.74 A: Yes, click "Disconnect & Reconnect" in Settings > BoxedChat Integration to select a different workspace. 72 75 73 76 **Q: How do I remove the widget?** … … 76 79 == Changelog == 77 80 78 = 1.2. 2=81 = 1.2.3 = 79 82 - Improved security with API key management 80 83 81 = 1. 2.1=84 = 1.1.0 = 82 85 - Switched to OAuth authentication flow 83 86 - Auto-embedding of widget on all pages … … 85 88 - Improved security with API key management 86 89 87 = 1. 1.0 =90 = 1.0.0 = 88 91 - Initial release -
boxedchat-chat-widget/trunk/boxedchat-chat-widget.php
r3496494 r3496550 1 1 <?php 2 2 /** 3 * Plugin Name: BoxedChat – AI Chat Widget & Support 3 * Plugin Name: BoxedChat – AI Chat Widget & Support & Helpdesk 4 4 * 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. 25 * Version: 1.2.3 6 6 * Author: boxedchat 7 7 * Author URI: https://boxed.chat … … 12 12 */ 13 13 14 15 14 if (!defined('ABSPATH')) exit; 16 15 … … 18 17 add_action('admin_init', function() { 19 18 if (!isset($_POST['boxchat_nonce'])) return; 20 21 19 if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['boxchat_nonce'])), 'boxchat_settings')) return; 22 23 20 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); 25 22 } 26 23 27 24 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'); 44 56 exit; 45 57 } … … 51 63 delete_option('boxchat_workspace_name'); 52 64 delete_option('boxchat_api_key'); 65 delete_option('boxchat_connection_token'); 53 66 54 67 wp_safe_redirect(admin_url('admin.php?page=boxchat-settings')); … … 75 88 $workspace_id = get_option('boxchat_workspace_id'); 76 89 $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 } 120 147 ?> 121 148 <div class="wrap">
Note: See TracChangeset
for help on using the changeset viewer.