Changeset 3791202
- Timestamp:
- 11/08/2026 04:28:35 PM (less than one hour ago)
- Location:
- cliedesk
- Files:
-
- 2 added
- 48 edited
- 1 copied
-
tags/1.2.4 (copied) (copied from cliedesk/trunk )
-
tags/1.2.4/changelog.txt (modified) (1 diff)
-
tags/1.2.4/cliedesk.php (modified) (2 diffs)
-
tags/1.2.4/readme.txt (modified) (3 diffs)
-
tags/1.2.4/src/App/Shell.php (modified) (2 diffs)
-
tags/1.2.4/src/Core/Plugin.php (modified) (2 diffs)
-
tags/1.2.4/src/Infrastructure/Files/FileLinks.php (modified) (1 diff)
-
tags/1.2.4/src/Infrastructure/Http/NoCache.php (added)
-
tags/1.2.4/src/Modules/Commerce/Account/EmailChange.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Core/ModuleSwitches.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Crm/Unsubscribe.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Csat/CsatPage.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Knowledge/Embeds.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Knowledge/HelpCenter.php (modified) (2 diffs)
-
tags/1.2.4/src/Modules/Knowledge/Lifecycle.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Knowledge/Redirects.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Portal/PortalModule.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Requests/RequestPage.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Widget/ChatPage.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Widget/CustomerSessions.php (modified) (1 diff)
-
tags/1.2.4/src/Modules/Widget/WidgetModule.php (modified) (2 diffs)
-
tags/1.2.4/src/Modules/Workspace/Actions/ProductUpdate.php (modified) (1 diff)
-
tags/1.2.4/src/Rest/RestServer.php (modified) (4 diffs)
-
tags/1.2.4/vendor/autoload.php (modified) (1 diff)
-
tags/1.2.4/vendor/composer/autoload_real.php (modified) (2 diffs)
-
tags/1.2.4/vendor/composer/autoload_static.php (modified) (2 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/cliedesk.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/src/App/Shell.php (modified) (2 diffs)
-
trunk/src/Core/Plugin.php (modified) (2 diffs)
-
trunk/src/Infrastructure/Files/FileLinks.php (modified) (1 diff)
-
trunk/src/Infrastructure/Http/NoCache.php (added)
-
trunk/src/Modules/Commerce/Account/EmailChange.php (modified) (1 diff)
-
trunk/src/Modules/Core/ModuleSwitches.php (modified) (1 diff)
-
trunk/src/Modules/Crm/Unsubscribe.php (modified) (1 diff)
-
trunk/src/Modules/Csat/CsatPage.php (modified) (1 diff)
-
trunk/src/Modules/Knowledge/Embeds.php (modified) (1 diff)
-
trunk/src/Modules/Knowledge/HelpCenter.php (modified) (2 diffs)
-
trunk/src/Modules/Knowledge/Lifecycle.php (modified) (1 diff)
-
trunk/src/Modules/Knowledge/Redirects.php (modified) (1 diff)
-
trunk/src/Modules/Portal/PortalModule.php (modified) (1 diff)
-
trunk/src/Modules/Requests/RequestPage.php (modified) (1 diff)
-
trunk/src/Modules/Widget/ChatPage.php (modified) (1 diff)
-
trunk/src/Modules/Widget/CustomerSessions.php (modified) (1 diff)
-
trunk/src/Modules/Widget/WidgetModule.php (modified) (2 diffs)
-
trunk/src/Modules/Workspace/Actions/ProductUpdate.php (modified) (1 diff)
-
trunk/src/Rest/RestServer.php (modified) (4 diffs)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
cliedesk/tags/1.2.4/changelog.txt
r3790823 r3791202 2 2 3 3 Full release notes. readme.txt shows a short summary of the current release. 4 5 = 1.2.4 = 6 * Security: LiteSpeed Cache's default "Cache REST API" kept public Cliedesk REST answers for a week and ignored the visitor's token header, so a chat list or a guest's portal conversation could be served to someone else. Every Cliedesk REST answer now refuses page caches in their own terms (LiteSpeed Cache API, DONOTCACHEPAGE, CDN headers). 7 * Fixed: with LiteSpeed Cache, the chat kept getting one saved answer: no replies, no "is typing", no read status; background jobs lost the traffic that starts them. 8 * Fixed: private pages (chat page, request form page, portal page, survey, unsubscribe, file links) tell every page cache not to store them; a password-protected or private help center too. 9 * Changed: public help pages and ordinary pages with the chat loader stay cacheable and refresh when public settings, modules or a product address change. Older cached answers are cleared once when the plugin updates. 10 * Fixed: the chat loader is excluded from LiteSpeed Cache's JavaScript combine and delay. 4 11 5 12 = 1.2.3 = -
cliedesk/tags/1.2.4/cliedesk.php
r3790823 r3791202 4 4 * Plugin URI: https://cliedesk.com/ 5 5 * Description: A complete, AI-ready helpdesk on your own WordPress server. Live chat, contact forms, email replies and a customer portal in one shared inbox, with a help center, automation, business hours, reports and live WooCommerce orders. Unlimited agents, and your data stays on your site. 6 * Version: 1.2. 36 * Version: 1.2.4 7 7 * Requires at least: 7.0 8 8 * Requires PHP: 8.1 … … 19 19 defined( 'ABSPATH' ) || exit; 20 20 21 define( 'CLIEDESK_VERSION', '1.2. 3' );21 define( 'CLIEDESK_VERSION', '1.2.4' ); 22 22 define( 'CLIEDESK_FILE', __FILE__ ); 23 23 define( 'CLIEDESK_DIR', __DIR__ . '/' ); -
cliedesk/tags/1.2.4/readme.txt
r3790823 r3791202 6 6 Tested up to: 7.1 7 7 Requires PHP: 8.1 8 Stable tag: 1.2. 38 Stable tag: 1.2.4 9 9 License: GPL-2.0-or-later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 149 149 == Changelog == 150 150 151 = 1.2.3 = 152 * Faster: fewer database queries per request, only the needed REST routes, smaller app files; conversations start loading on the click. 153 * New: a six-step setup assistant; notifications for new unassigned conversations; "New article" on the Knowledge page. 154 * Fixed: saving secrets without the sodium extension; mismatched SMTP port and encryption; searches with a hyphen (SKU-4711). 151 = 1.2.4 = 152 * Security: with LiteSpeed Cache's default settings, a visitor's chat list and a guest's portal conversations could be served to other people. Cliedesk's data is now never stored by page caches. Please update. 153 * Fixed: with LiteSpeed Cache, agent replies and "is typing" did not reach the chat, and read status was not recorded. 154 * Fixed: password-protected help centers are no longer stored by page caches. Public help pages stay cached and refresh when articles or settings change. 155 * Fixed: LiteSpeed Cache's combine and delay options no longer stop the chat from starting. 155 156 156 157 Full notes and older entries are in changelog.txt. … … 158 159 == Upgrade Notice == 159 160 161 = 1.2.4 = 162 Security update for sites using LiteSpeed Cache: private chat data could be served to other visitors, and chat replies did not arrive. Please update. 163 160 164 = 1.2.3 = 161 165 A faster app, chat widget and inbox, a new six-step setup assistant, and fixes for saving secrets and SMTP settings. -
cliedesk/tags/1.2.4/src/App/Shell.php
r3777980 r3791202 167 167 return; 168 168 } 169 nocache_headers(); 170 header( 'Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0' ); 171 header( 'CDN-Cache-Control: no-store' ); 172 header( 'Cloudflare-CDN-Cache-Control: no-store' ); 173 header( 'Surrogate-Control: no-store' ); 174 header( 'X-LiteSpeed-Cache-Control: no-cache' ); 175 header( 'X-Accel-Expires: 0' ); 169 \Cliedesk\Infrastructure\Http\NoCache::page(); 176 170 header( 'Vary: Cookie', false ); 177 171 // The app is never framed by another site, never sniffed as another type, and asks only for the microphone … … 182 176 header( 'Referrer-Policy: strict-origin-when-cross-origin' ); 183 177 header( 'Permissions-Policy: camera=(), geolocation=(), payment=(), usb=(), microphone=(self)' ); 184 do_action( 'litespeed_control_set_nocache', 'cliedesk app' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- LiteSpeed Cache API.185 178 } 186 179 -
cliedesk/tags/1.2.4/src/Core/Plugin.php
r3790823 r3791202 155 155 add_action( 'init', array( self::class, 'register_modules' ), 1 ); 156 156 add_action( 'init', array( self::class, 'maybe_upgrade' ), 2 ); 157 \Cliedesk\Infrastructure\Http\NoCache::hooks(); 157 158 add_action( Installer::MIGRATE_HOOK, array( Installer::class, 'run_background_batch' ) ); 158 159 add_action( Installer::NETWORK_INSTALL_HOOK, array( Installer::class, 'run_network_install' ) ); … … 490 491 Installer::seed( self::container()->get( Db::class ), self::container()->get( Clock::class ) ); 491 492 Installer::add_capabilities(); 493 // Answers cached by an earlier version would otherwise be served until they expire. 494 \Cliedesk\Infrastructure\Http\NoCache::purge_all(); 492 495 self::update_core_option( 493 496 array( -
cliedesk/tags/1.2.4/src/Infrastructure/Files/FileLinks.php
r3777980 r3791202 178 178 ); 179 179 // phpcs:enable WordPress.Security.NonceVerification.Recommended 180 nocache_headers();180 \Cliedesk\Infrastructure\Http\NoCache::page(); 181 181 header( 'X-Content-Type-Options: nosniff' ); 182 182 header( 'Referrer-Policy: no-referrer' ); -
cliedesk/tags/1.2.4/src/Modules/Commerce/Account/EmailChange.php
r3787995 r3791202 231 231 $out = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token ); 232 232 status_header( $out['status'] ); 233 nocache_headers();233 \Cliedesk\Infrastructure\Http\NoCache::page(); 234 234 header( 'Content-Type: text/html; charset=utf-8' ); 235 235 header( 'X-Robots-Tag: noindex' ); -
cliedesk/tags/1.2.4/src/Modules/Core/ModuleSwitches.php
r3787995 r3791202 146 146 $stopped = $this->modules->resolve_off( $off ); 147 147 update_option( ModuleRegistry::OFF_OPTION, $off, true ); 148 \Cliedesk\Infrastructure\Http\NoCache::purge_public(); 148 149 // Pages of modules that stop or start (the portal address) change the rewrite rules on the next request. 149 150 $this->router?->request_flush(); -
cliedesk/tags/1.2.4/src/Modules/Crm/Unsubscribe.php
r3747777 r3791202 101 101 $out = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token ); 102 102 status_header( $out['status'] ); 103 nocache_headers();103 \Cliedesk\Infrastructure\Http\NoCache::page(); 104 104 header( 'Content-Type: text/html; charset=utf-8' ); 105 105 header( 'X-Robots-Tag: noindex' ); -
cliedesk/tags/1.2.4/src/Modules/Csat/CsatPage.php
r3747777 r3791202 45 45 } 46 46 $response = $this->surveys->by_token( $token ); 47 nocache_headers();47 \Cliedesk\Infrastructure\Http\NoCache::page(); 48 48 header( 'X-Robots-Tag: noindex, nofollow' ); 49 49 header( 'Referrer-Policy: no-referrer' ); -
cliedesk/tags/1.2.4/src/Modules/Knowledge/Embeds.php
r3777980 r3791202 92 92 public function render( int $id, bool $title = true ): string { 93 93 $post = $id > 0 ? get_post( $id ) : null; 94 if ( ! HelpCenter::is_public() ) { 95 \Cliedesk\Infrastructure\Http\NoCache::refuse(); // What this visitor sees here is not what everyone sees. 96 } 94 97 if ( ! $post instanceof \WP_Post || Articles::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status || ! Articles::can_read( $id ) || isset( self::$rendering[ $id ] ) ) { 95 98 return ''; -
cliedesk/tags/1.2.4/src/Modules/Knowledge/HelpCenter.php
r3777980 r3791202 36 36 add_filter( 'template_include', array( $this, 'classic_template' ), 20 ); 37 37 add_action( 'wp_enqueue_scripts', array( $this, 'assets' ) ); 38 add_action( 'template_redirect', array( self::class, 'cache_policy' ), 0 ); 38 39 add_filter( 'body_class', array( $this, 'body_class' ) ); 39 40 // KB-37: the help-center search on any page (the block works too). … … 46 47 public static function is_help(): bool { 47 48 return is_post_type_archive( Articles::POST_TYPE ) || is_tax( Articles::TAXONOMY ) || is_singular( Articles::POST_TYPE ); 49 } 50 51 /** 52 * What a page cache may do with this help page: keep it while the help center is public (the same for everyone, 53 * refreshed when an article or a setting changes), never store it when it is private. A visitor who unlocked a 54 * password-protected help center must not fill the cache for everyone else. 55 */ 56 public static function cache_policy(): void { 57 if ( ! self::is_help() ) { 58 return; 59 } 60 if ( self::is_public() ) { 61 \Cliedesk\Infrastructure\Http\NoCache::tag_public(); 62 return; 63 } 64 \Cliedesk\Infrastructure\Http\NoCache::page(); 48 65 } 49 66 -
cliedesk/tags/1.2.4/src/Modules/Knowledge/Lifecycle.php
r3747777 r3791202 142 142 } 143 143 status_header( 410 ); 144 nocache_headers();144 \Cliedesk\Infrastructure\Http\NoCache::page(); 145 145 } 146 146 -
cliedesk/tags/1.2.4/src/Modules/Knowledge/Redirects.php
r3747777 r3791202 143 143 $wp_query->query( array( 'post_type' => Articles::POST_TYPE ) ); 144 144 status_header( 404 ); 145 nocache_headers();145 \Cliedesk\Infrastructure\Http\NoCache::page(); 146 146 } 147 147 -
cliedesk/tags/1.2.4/src/Modules/Portal/PortalModule.php
r3789063 r3791202 153 153 'template_redirect', 154 154 static function (): void { 155 if ( isset( $_GET[ PortalAccess::QUERY_ARG ] ) && ! headers_sent() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a link token is present. 156 nocache_headers(); 155 $link = isset( $_GET[ PortalAccess::QUERY_ARG ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a link token is present. 156 if ( $link || self::on_portal_page() ) { 157 \Cliedesk\Infrastructure\Http\NoCache::page(); 158 } 159 if ( $link && ! headers_sent() ) { 157 160 header( 'Referrer-Policy: no-referrer' ); 158 }159 // FA-L7: a portal page in the language a visitor picked is never cached for everyone else.160 if ( ( isset( $_GET[ self::LANG_ARG ] ) || isset( $_COOKIE[ self::LANG_COOKIE ] ) ) && ! headers_sent() && self::on_portal_page() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a language was picked.161 nocache_headers();162 161 } 163 162 self::remember_language(); -
cliedesk/tags/1.2.4/src/Modules/Requests/RequestPage.php
r3790823 r3791202 82 82 $type = sanitize_key( (string) get_query_var( 'cliedesk_request_type' ) ); 83 83 $product = isset( $_GET['product'] ) ? sanitize_title( wp_unslash( (string) $_GET['product'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- a public link; only chooses the product. 84 nocache_headers();84 \Cliedesk\Infrastructure\Http\NoCache::page(); 85 85 header( 'X-Robots-Tag: noindex' ); 86 86 header( 'Content-Security-Policy: ' . self::frame_ancestors( (string) $this->settings->get( 'requests.embed_origins' ) ) ); -
cliedesk/tags/1.2.4/src/Modules/Widget/ChatPage.php
r3790823 r3791202 141 141 if ( null === $config ) { 142 142 status_header( 404 ); 143 nocache_headers();143 \Cliedesk\Infrastructure\Http\NoCache::page(); 144 144 exit; 145 145 } 146 nocache_headers();146 \Cliedesk\Infrastructure\Http\NoCache::page(); 147 147 header( 'X-Robots-Tag: noindex' ); 148 148 // Security review M2: like the hosted request form, only this site and the widget's trusted domains may frame it. -
cliedesk/tags/1.2.4/src/Modules/Widget/CustomerSessions.php
r3787995 r3791202 112 112 */ 113 113 public function identity(): void { 114 nocache_headers();114 \Cliedesk\Infrastructure\Http\NoCache::page(); 115 115 wp_send_json( $this->proof( isset( $_GET['product'] ) ? sanitize_key( wp_unslash( (string) $_GET['product'] ) ) : '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only, same-site; the answer is about the current user only. 116 116 } -
cliedesk/tags/1.2.4/src/Modules/Widget/WidgetModule.php
r3787995 r3791202 936 936 return; 937 937 } 938 // The page carries the public config: a cached copy is refreshed when the settings change. 939 \Cliedesk\Infrastructure\Http\NoCache::tag_public(); 938 940 wp_enqueue_script( 939 941 'cliedesk-widget', … … 953 955 return $tag; 954 956 } 955 // The public config travels with the script: no extra request on the site itself. 956 return str_replace( ' src=', ' data-config="' . esc_attr( (string) wp_json_encode( $config ) ) . '" src=', $tag ); 957 // The public config travels with the script: no extra request on the site itself. The loader finds that 958 // config through its own tag, so an optimizer must not merge or delay it (LiteSpeed Cache: these attributes). 959 return str_replace( ' src=', ' data-no-optimize="1" data-no-defer="1" data-config="' . esc_attr( (string) wp_json_encode( $config ) ) . '" src=', $tag ); 957 960 }, 958 961 10, -
cliedesk/tags/1.2.4/src/Modules/Workspace/Actions/ProductUpdate.php
r3747777 r3791202 113 113 if ( array() !== $columns ) { 114 114 $version = $this->ws->products->update( (int) $row['id'], $columns, $version ); 115 \Cliedesk\Infrastructure\Http\NoCache::purge_public(); // Cached pages carry the product's address. 115 116 } 116 117 if ( array_key_exists( 'mappings', $input ) ) { -
cliedesk/tags/1.2.4/src/Rest/RestServer.php
r3790823 r3791202 19 19 use Cliedesk\Infrastructure\ChangeLog; 20 20 use Cliedesk\Infrastructure\Ephemeral; 21 use Cliedesk\Infrastructure\Http\NoCache; 21 22 use Cliedesk\Infrastructure\Jobs\Kick; 22 23 use Cliedesk\Infrastructure\RequestId; … … 78 79 add_filter( 'rest_pre_dispatch', array( $this, 'complete_routes' ), 0, 3 ); 79 80 add_filter( 'rest_pre_dispatch', array( $this, 'guard' ), 10, 3 ); 81 add_filter( 'rest_pre_dispatch', array( $this, 'never_cache' ), 0, 3 ); 80 82 add_filter( 'rest_post_dispatch', array( $this, 'headers' ), 10, 3 ); 81 83 add_filter( 'rest_index', array( $this, 'trim_index' ) ); … … 273 275 274 276 /** 275 * Add X-Request-Id and no-store headers to cliedesk/v1 responses. 277 * `rest_pre_dispatch`: a page cache never stores a Cliedesk answer, streams and early exits included. Only for a 278 * real REST request: a route called from inside a normal page does not make that page uncacheable. 279 * 280 * @param mixed $result Result so far. 281 * @param \WP_REST_Server $server Server. 282 * @param \WP_REST_Request $request Request. 283 * @return mixed 284 */ 285 public function never_cache( $result, $server, $request ) { 286 if ( defined( 'REST_REQUEST' ) && REST_REQUEST && NoCache::is_own_route( (string) $request->get_route() ) ) { 287 NoCache::refuse(); 288 } 289 return $result; 290 } 291 292 /** 293 * Add the no-cache headers to Cliedesk's responses, and X-Request-Id and no-store to cliedesk/v1 responses. 276 294 * 277 295 * @param \WP_HTTP_Response $response Response. … … 281 299 */ 282 300 public function headers( $response, $server, $request ) { 283 if ( str_starts_with( (string) $request->get_route(), '/' . RouteRegistry::NAMESPACE ) ) { 301 $route = (string) $request->get_route(); 302 if ( ! NoCache::is_own_route( $route ) ) { 303 return $response; 304 } 305 foreach ( NoCache::headers() as $name => $value ) { 306 $response->header( $name, $value ); 307 } 308 if ( 0 === stripos( $route, '/' . RouteRegistry::NAMESPACE ) ) { 284 309 $response->header( 'X-Request-Id', RequestId::get() ); 285 310 $response->header( 'Cache-Control', 'no-store, private' ); -
cliedesk/tags/1.2.4/vendor/autoload.php
r3790823 r3791202 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef::getLoader();25 return ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f::getLoader(); -
cliedesk/tags/1.2.4/vendor/composer/autoload_real.php
r3790823 r3791202 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef5 class ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::getInitializer($loader)); 33 33 34 34 $loader->setClassMapAuthoritative(true); -
cliedesk/tags/1.2.4/vendor/composer/autoload_static.php
r3790823 r3791202 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef7 class ComposerStaticInit508f8c01434f52142bdea5cdb512e43f 8 8 { 9 9 public static $classMap = array ( … … 14 14 { 15 15 return \Closure::bind(function () use ($loader) { 16 $loader->classMap = ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef::$classMap;16 $loader->classMap = ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::$classMap; 17 17 18 18 }, null, ClassLoader::class); -
cliedesk/trunk/changelog.txt
r3790823 r3791202 2 2 3 3 Full release notes. readme.txt shows a short summary of the current release. 4 5 = 1.2.4 = 6 * Security: LiteSpeed Cache's default "Cache REST API" kept public Cliedesk REST answers for a week and ignored the visitor's token header, so a chat list or a guest's portal conversation could be served to someone else. Every Cliedesk REST answer now refuses page caches in their own terms (LiteSpeed Cache API, DONOTCACHEPAGE, CDN headers). 7 * Fixed: with LiteSpeed Cache, the chat kept getting one saved answer: no replies, no "is typing", no read status; background jobs lost the traffic that starts them. 8 * Fixed: private pages (chat page, request form page, portal page, survey, unsubscribe, file links) tell every page cache not to store them; a password-protected or private help center too. 9 * Changed: public help pages and ordinary pages with the chat loader stay cacheable and refresh when public settings, modules or a product address change. Older cached answers are cleared once when the plugin updates. 10 * Fixed: the chat loader is excluded from LiteSpeed Cache's JavaScript combine and delay. 4 11 5 12 = 1.2.3 = -
cliedesk/trunk/cliedesk.php
r3790823 r3791202 4 4 * Plugin URI: https://cliedesk.com/ 5 5 * Description: A complete, AI-ready helpdesk on your own WordPress server. Live chat, contact forms, email replies and a customer portal in one shared inbox, with a help center, automation, business hours, reports and live WooCommerce orders. Unlimited agents, and your data stays on your site. 6 * Version: 1.2. 36 * Version: 1.2.4 7 7 * Requires at least: 7.0 8 8 * Requires PHP: 8.1 … … 19 19 defined( 'ABSPATH' ) || exit; 20 20 21 define( 'CLIEDESK_VERSION', '1.2. 3' );21 define( 'CLIEDESK_VERSION', '1.2.4' ); 22 22 define( 'CLIEDESK_FILE', __FILE__ ); 23 23 define( 'CLIEDESK_DIR', __DIR__ . '/' ); -
cliedesk/trunk/readme.txt
r3790823 r3791202 6 6 Tested up to: 7.1 7 7 Requires PHP: 8.1 8 Stable tag: 1.2. 38 Stable tag: 1.2.4 9 9 License: GPL-2.0-or-later 10 10 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 149 149 == Changelog == 150 150 151 = 1.2.3 = 152 * Faster: fewer database queries per request, only the needed REST routes, smaller app files; conversations start loading on the click. 153 * New: a six-step setup assistant; notifications for new unassigned conversations; "New article" on the Knowledge page. 154 * Fixed: saving secrets without the sodium extension; mismatched SMTP port and encryption; searches with a hyphen (SKU-4711). 151 = 1.2.4 = 152 * Security: with LiteSpeed Cache's default settings, a visitor's chat list and a guest's portal conversations could be served to other people. Cliedesk's data is now never stored by page caches. Please update. 153 * Fixed: with LiteSpeed Cache, agent replies and "is typing" did not reach the chat, and read status was not recorded. 154 * Fixed: password-protected help centers are no longer stored by page caches. Public help pages stay cached and refresh when articles or settings change. 155 * Fixed: LiteSpeed Cache's combine and delay options no longer stop the chat from starting. 155 156 156 157 Full notes and older entries are in changelog.txt. … … 158 159 == Upgrade Notice == 159 160 161 = 1.2.4 = 162 Security update for sites using LiteSpeed Cache: private chat data could be served to other visitors, and chat replies did not arrive. Please update. 163 160 164 = 1.2.3 = 161 165 A faster app, chat widget and inbox, a new six-step setup assistant, and fixes for saving secrets and SMTP settings. -
cliedesk/trunk/src/App/Shell.php
r3777980 r3791202 167 167 return; 168 168 } 169 nocache_headers(); 170 header( 'Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0' ); 171 header( 'CDN-Cache-Control: no-store' ); 172 header( 'Cloudflare-CDN-Cache-Control: no-store' ); 173 header( 'Surrogate-Control: no-store' ); 174 header( 'X-LiteSpeed-Cache-Control: no-cache' ); 175 header( 'X-Accel-Expires: 0' ); 169 \Cliedesk\Infrastructure\Http\NoCache::page(); 176 170 header( 'Vary: Cookie', false ); 177 171 // The app is never framed by another site, never sniffed as another type, and asks only for the microphone … … 182 176 header( 'Referrer-Policy: strict-origin-when-cross-origin' ); 183 177 header( 'Permissions-Policy: camera=(), geolocation=(), payment=(), usb=(), microphone=(self)' ); 184 do_action( 'litespeed_control_set_nocache', 'cliedesk app' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- LiteSpeed Cache API.185 178 } 186 179 -
cliedesk/trunk/src/Core/Plugin.php
r3790823 r3791202 155 155 add_action( 'init', array( self::class, 'register_modules' ), 1 ); 156 156 add_action( 'init', array( self::class, 'maybe_upgrade' ), 2 ); 157 \Cliedesk\Infrastructure\Http\NoCache::hooks(); 157 158 add_action( Installer::MIGRATE_HOOK, array( Installer::class, 'run_background_batch' ) ); 158 159 add_action( Installer::NETWORK_INSTALL_HOOK, array( Installer::class, 'run_network_install' ) ); … … 490 491 Installer::seed( self::container()->get( Db::class ), self::container()->get( Clock::class ) ); 491 492 Installer::add_capabilities(); 493 // Answers cached by an earlier version would otherwise be served until they expire. 494 \Cliedesk\Infrastructure\Http\NoCache::purge_all(); 492 495 self::update_core_option( 493 496 array( -
cliedesk/trunk/src/Infrastructure/Files/FileLinks.php
r3777980 r3791202 178 178 ); 179 179 // phpcs:enable WordPress.Security.NonceVerification.Recommended 180 nocache_headers();180 \Cliedesk\Infrastructure\Http\NoCache::page(); 181 181 header( 'X-Content-Type-Options: nosniff' ); 182 182 header( 'Referrer-Policy: no-referrer' ); -
cliedesk/trunk/src/Modules/Commerce/Account/EmailChange.php
r3787995 r3791202 231 231 $out = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token ); 232 232 status_header( $out['status'] ); 233 nocache_headers();233 \Cliedesk\Infrastructure\Http\NoCache::page(); 234 234 header( 'Content-Type: text/html; charset=utf-8' ); 235 235 header( 'X-Robots-Tag: noindex' ); -
cliedesk/trunk/src/Modules/Core/ModuleSwitches.php
r3787995 r3791202 146 146 $stopped = $this->modules->resolve_off( $off ); 147 147 update_option( ModuleRegistry::OFF_OPTION, $off, true ); 148 \Cliedesk\Infrastructure\Http\NoCache::purge_public(); 148 149 // Pages of modules that stop or start (the portal address) change the rewrite rules on the next request. 149 150 $this->router?->request_flush(); -
cliedesk/trunk/src/Modules/Crm/Unsubscribe.php
r3747777 r3791202 101 101 $out = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token ); 102 102 status_header( $out['status'] ); 103 nocache_headers();103 \Cliedesk\Infrastructure\Http\NoCache::page(); 104 104 header( 'Content-Type: text/html; charset=utf-8' ); 105 105 header( 'X-Robots-Tag: noindex' ); -
cliedesk/trunk/src/Modules/Csat/CsatPage.php
r3747777 r3791202 45 45 } 46 46 $response = $this->surveys->by_token( $token ); 47 nocache_headers();47 \Cliedesk\Infrastructure\Http\NoCache::page(); 48 48 header( 'X-Robots-Tag: noindex, nofollow' ); 49 49 header( 'Referrer-Policy: no-referrer' ); -
cliedesk/trunk/src/Modules/Knowledge/Embeds.php
r3777980 r3791202 92 92 public function render( int $id, bool $title = true ): string { 93 93 $post = $id > 0 ? get_post( $id ) : null; 94 if ( ! HelpCenter::is_public() ) { 95 \Cliedesk\Infrastructure\Http\NoCache::refuse(); // What this visitor sees here is not what everyone sees. 96 } 94 97 if ( ! $post instanceof \WP_Post || Articles::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status || ! Articles::can_read( $id ) || isset( self::$rendering[ $id ] ) ) { 95 98 return ''; -
cliedesk/trunk/src/Modules/Knowledge/HelpCenter.php
r3777980 r3791202 36 36 add_filter( 'template_include', array( $this, 'classic_template' ), 20 ); 37 37 add_action( 'wp_enqueue_scripts', array( $this, 'assets' ) ); 38 add_action( 'template_redirect', array( self::class, 'cache_policy' ), 0 ); 38 39 add_filter( 'body_class', array( $this, 'body_class' ) ); 39 40 // KB-37: the help-center search on any page (the block works too). … … 46 47 public static function is_help(): bool { 47 48 return is_post_type_archive( Articles::POST_TYPE ) || is_tax( Articles::TAXONOMY ) || is_singular( Articles::POST_TYPE ); 49 } 50 51 /** 52 * What a page cache may do with this help page: keep it while the help center is public (the same for everyone, 53 * refreshed when an article or a setting changes), never store it when it is private. A visitor who unlocked a 54 * password-protected help center must not fill the cache for everyone else. 55 */ 56 public static function cache_policy(): void { 57 if ( ! self::is_help() ) { 58 return; 59 } 60 if ( self::is_public() ) { 61 \Cliedesk\Infrastructure\Http\NoCache::tag_public(); 62 return; 63 } 64 \Cliedesk\Infrastructure\Http\NoCache::page(); 48 65 } 49 66 -
cliedesk/trunk/src/Modules/Knowledge/Lifecycle.php
r3747777 r3791202 142 142 } 143 143 status_header( 410 ); 144 nocache_headers();144 \Cliedesk\Infrastructure\Http\NoCache::page(); 145 145 } 146 146 -
cliedesk/trunk/src/Modules/Knowledge/Redirects.php
r3747777 r3791202 143 143 $wp_query->query( array( 'post_type' => Articles::POST_TYPE ) ); 144 144 status_header( 404 ); 145 nocache_headers();145 \Cliedesk\Infrastructure\Http\NoCache::page(); 146 146 } 147 147 -
cliedesk/trunk/src/Modules/Portal/PortalModule.php
r3789063 r3791202 153 153 'template_redirect', 154 154 static function (): void { 155 if ( isset( $_GET[ PortalAccess::QUERY_ARG ] ) && ! headers_sent() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a link token is present. 156 nocache_headers(); 155 $link = isset( $_GET[ PortalAccess::QUERY_ARG ] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a link token is present. 156 if ( $link || self::on_portal_page() ) { 157 \Cliedesk\Infrastructure\Http\NoCache::page(); 158 } 159 if ( $link && ! headers_sent() ) { 157 160 header( 'Referrer-Policy: no-referrer' ); 158 }159 // FA-L7: a portal page in the language a visitor picked is never cached for everyone else.160 if ( ( isset( $_GET[ self::LANG_ARG ] ) || isset( $_COOKIE[ self::LANG_COOKIE ] ) ) && ! headers_sent() && self::on_portal_page() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only checks that a language was picked.161 nocache_headers();162 161 } 163 162 self::remember_language(); -
cliedesk/trunk/src/Modules/Requests/RequestPage.php
r3790823 r3791202 82 82 $type = sanitize_key( (string) get_query_var( 'cliedesk_request_type' ) ); 83 83 $product = isset( $_GET['product'] ) ? sanitize_title( wp_unslash( (string) $_GET['product'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- a public link; only chooses the product. 84 nocache_headers();84 \Cliedesk\Infrastructure\Http\NoCache::page(); 85 85 header( 'X-Robots-Tag: noindex' ); 86 86 header( 'Content-Security-Policy: ' . self::frame_ancestors( (string) $this->settings->get( 'requests.embed_origins' ) ) ); -
cliedesk/trunk/src/Modules/Widget/ChatPage.php
r3790823 r3791202 141 141 if ( null === $config ) { 142 142 status_header( 404 ); 143 nocache_headers();143 \Cliedesk\Infrastructure\Http\NoCache::page(); 144 144 exit; 145 145 } 146 nocache_headers();146 \Cliedesk\Infrastructure\Http\NoCache::page(); 147 147 header( 'X-Robots-Tag: noindex' ); 148 148 // Security review M2: like the hosted request form, only this site and the widget's trusted domains may frame it. -
cliedesk/trunk/src/Modules/Widget/CustomerSessions.php
r3787995 r3791202 112 112 */ 113 113 public function identity(): void { 114 nocache_headers();114 \Cliedesk\Infrastructure\Http\NoCache::page(); 115 115 wp_send_json( $this->proof( isset( $_GET['product'] ) ? sanitize_key( wp_unslash( (string) $_GET['product'] ) ) : '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only, same-site; the answer is about the current user only. 116 116 } -
cliedesk/trunk/src/Modules/Widget/WidgetModule.php
r3787995 r3791202 936 936 return; 937 937 } 938 // The page carries the public config: a cached copy is refreshed when the settings change. 939 \Cliedesk\Infrastructure\Http\NoCache::tag_public(); 938 940 wp_enqueue_script( 939 941 'cliedesk-widget', … … 953 955 return $tag; 954 956 } 955 // The public config travels with the script: no extra request on the site itself. 956 return str_replace( ' src=', ' data-config="' . esc_attr( (string) wp_json_encode( $config ) ) . '" src=', $tag ); 957 // The public config travels with the script: no extra request on the site itself. The loader finds that 958 // config through its own tag, so an optimizer must not merge or delay it (LiteSpeed Cache: these attributes). 959 return str_replace( ' src=', ' data-no-optimize="1" data-no-defer="1" data-config="' . esc_attr( (string) wp_json_encode( $config ) ) . '" src=', $tag ); 957 960 }, 958 961 10, -
cliedesk/trunk/src/Modules/Workspace/Actions/ProductUpdate.php
r3747777 r3791202 113 113 if ( array() !== $columns ) { 114 114 $version = $this->ws->products->update( (int) $row['id'], $columns, $version ); 115 \Cliedesk\Infrastructure\Http\NoCache::purge_public(); // Cached pages carry the product's address. 115 116 } 116 117 if ( array_key_exists( 'mappings', $input ) ) { -
cliedesk/trunk/src/Rest/RestServer.php
r3790823 r3791202 19 19 use Cliedesk\Infrastructure\ChangeLog; 20 20 use Cliedesk\Infrastructure\Ephemeral; 21 use Cliedesk\Infrastructure\Http\NoCache; 21 22 use Cliedesk\Infrastructure\Jobs\Kick; 22 23 use Cliedesk\Infrastructure\RequestId; … … 78 79 add_filter( 'rest_pre_dispatch', array( $this, 'complete_routes' ), 0, 3 ); 79 80 add_filter( 'rest_pre_dispatch', array( $this, 'guard' ), 10, 3 ); 81 add_filter( 'rest_pre_dispatch', array( $this, 'never_cache' ), 0, 3 ); 80 82 add_filter( 'rest_post_dispatch', array( $this, 'headers' ), 10, 3 ); 81 83 add_filter( 'rest_index', array( $this, 'trim_index' ) ); … … 273 275 274 276 /** 275 * Add X-Request-Id and no-store headers to cliedesk/v1 responses. 277 * `rest_pre_dispatch`: a page cache never stores a Cliedesk answer, streams and early exits included. Only for a 278 * real REST request: a route called from inside a normal page does not make that page uncacheable. 279 * 280 * @param mixed $result Result so far. 281 * @param \WP_REST_Server $server Server. 282 * @param \WP_REST_Request $request Request. 283 * @return mixed 284 */ 285 public function never_cache( $result, $server, $request ) { 286 if ( defined( 'REST_REQUEST' ) && REST_REQUEST && NoCache::is_own_route( (string) $request->get_route() ) ) { 287 NoCache::refuse(); 288 } 289 return $result; 290 } 291 292 /** 293 * Add the no-cache headers to Cliedesk's responses, and X-Request-Id and no-store to cliedesk/v1 responses. 276 294 * 277 295 * @param \WP_HTTP_Response $response Response. … … 281 299 */ 282 300 public function headers( $response, $server, $request ) { 283 if ( str_starts_with( (string) $request->get_route(), '/' . RouteRegistry::NAMESPACE ) ) { 301 $route = (string) $request->get_route(); 302 if ( ! NoCache::is_own_route( $route ) ) { 303 return $response; 304 } 305 foreach ( NoCache::headers() as $name => $value ) { 306 $response->header( $name, $value ); 307 } 308 if ( 0 === stripos( $route, '/' . RouteRegistry::NAMESPACE ) ) { 284 309 $response->header( 'X-Request-Id', RequestId::get() ); 285 310 $response->header( 'Cache-Control', 'no-store, private' ); -
cliedesk/trunk/vendor/autoload.php
r3790823 r3791202 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef::getLoader();25 return ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f::getLoader(); -
cliedesk/trunk/vendor/composer/autoload_real.php
r3790823 r3791202 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef5 class ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit5 ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::getInitializer($loader)); 33 33 34 34 $loader->setClassMapAuthoritative(true); -
cliedesk/trunk/vendor/composer/autoload_static.php
r3790823 r3791202 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef7 class ComposerStaticInit508f8c01434f52142bdea5cdb512e43f 8 8 { 9 9 public static $classMap = array ( … … 14 14 { 15 15 return \Closure::bind(function () use ($loader) { 16 $loader->classMap = ComposerStaticInit5 ca9f3f659c1c103c5481660e5e322ef::$classMap;16 $loader->classMap = ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::$classMap; 17 17 18 18 }, null, ClassLoader::class);
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)