Plugin Directory

Changeset 3791202


Ignore:
Timestamp:
11/08/2026 04:28:35 PM (less than one hour ago)
Author:
degird
Message:

Release 1.2.4

Location:
cliedesk
Files:
2 added
48 edited
1 copied

Legend:

Unmodified
Added
Removed
  • cliedesk/tags/1.2.4/changelog.txt

    r3790823 r3791202  
    22
    33Full 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.
    411
    512= 1.2.3 =
  • cliedesk/tags/1.2.4/cliedesk.php

    r3790823 r3791202  
    44 * Plugin URI:        https://cliedesk.com/
    55 * 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.3
     6 * Version:           1.2.4
    77 * Requires at least: 7.0
    88 * Requires PHP:      8.1
    … …  
    1919defined( 'ABSPATH' ) || exit;
    2020
    21 define( 'CLIEDESK_VERSION', '1.2.3' );
     21define( 'CLIEDESK_VERSION', '1.2.4' );
    2222define( 'CLIEDESK_FILE', __FILE__ );
    2323define( 'CLIEDESK_DIR', __DIR__ . '/' );
  • cliedesk/tags/1.2.4/readme.txt

    r3790823 r3791202  
    66Tested up to: 7.1
    77Requires PHP: 8.1
    8 Stable tag: 1.2.3
     8Stable tag: 1.2.4
    99License: GPL-2.0-or-later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    149149== Changelog ==
    150150
    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.
    155156
    156157Full notes and older entries are in changelog.txt.
    … …  
    158159== Upgrade Notice ==
    159160
     161= 1.2.4 =
     162Security update for sites using LiteSpeed Cache: private chat data could be served to other visitors, and chat replies did not arrive. Please update.
     163
    160164= 1.2.3 =
    161165A 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  
    167167                        return;
    168168                }
    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();
    176170                header( 'Vary: Cookie', false );
    177171                // The app is never framed by another site, never sniffed as another type, and asks only for the microphone
    … …  
    182176                header( 'Referrer-Policy: strict-origin-when-cross-origin' );
    183177                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.
    185178        }
    186179
  • cliedesk/tags/1.2.4/src/Core/Plugin.php

    r3790823 r3791202  
    155155                add_action( 'init', array( self::class, 'register_modules' ), 1 );
    156156                add_action( 'init', array( self::class, 'maybe_upgrade' ), 2 );
     157                \Cliedesk\Infrastructure\Http\NoCache::hooks();
    157158                add_action( Installer::MIGRATE_HOOK, array( Installer::class, 'run_background_batch' ) );
    158159                add_action( Installer::NETWORK_INSTALL_HOOK, array( Installer::class, 'run_network_install' ) );
    … …  
    490491                        Installer::seed( self::container()->get( Db::class ), self::container()->get( Clock::class ) );
    491492                        Installer::add_capabilities();
     493                        // Answers cached by an earlier version would otherwise be served until they expire.
     494                        \Cliedesk\Infrastructure\Http\NoCache::purge_all();
    492495                        self::update_core_option(
    493496                                array(
  • cliedesk/tags/1.2.4/src/Infrastructure/Files/FileLinks.php

    r3777980 r3791202  
    178178                );
    179179                // phpcs:enable WordPress.Security.NonceVerification.Recommended
    180                 nocache_headers();
     180                \Cliedesk\Infrastructure\Http\NoCache::page();
    181181                header( 'X-Content-Type-Options: nosniff' );
    182182                header( 'Referrer-Policy: no-referrer' );
  • cliedesk/tags/1.2.4/src/Modules/Commerce/Account/EmailChange.php

    r3787995 r3791202  
    231231                $out    = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token );
    232232                status_header( $out['status'] );
    233                 nocache_headers();
     233                \Cliedesk\Infrastructure\Http\NoCache::page();
    234234                header( 'Content-Type: text/html; charset=utf-8' );
    235235                header( 'X-Robots-Tag: noindex' );
  • cliedesk/tags/1.2.4/src/Modules/Core/ModuleSwitches.php

    r3787995 r3791202  
    146146                $stopped = $this->modules->resolve_off( $off );
    147147                update_option( ModuleRegistry::OFF_OPTION, $off, true );
     148                \Cliedesk\Infrastructure\Http\NoCache::purge_public();
    148149                // Pages of modules that stop or start (the portal address) change the rewrite rules on the next request.
    149150                $this->router?->request_flush();
  • cliedesk/tags/1.2.4/src/Modules/Crm/Unsubscribe.php

    r3747777 r3791202  
    101101                $out    = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token );
    102102                status_header( $out['status'] );
    103                 nocache_headers();
     103                \Cliedesk\Infrastructure\Http\NoCache::page();
    104104                header( 'Content-Type: text/html; charset=utf-8' );
    105105                header( 'X-Robots-Tag: noindex' );
  • cliedesk/tags/1.2.4/src/Modules/Csat/CsatPage.php

    r3747777 r3791202  
    4545                }
    4646                $response = $this->surveys->by_token( $token );
    47                 nocache_headers();
     47                \Cliedesk\Infrastructure\Http\NoCache::page();
    4848                header( 'X-Robots-Tag: noindex, nofollow' );
    4949                header( 'Referrer-Policy: no-referrer' );
  • cliedesk/tags/1.2.4/src/Modules/Knowledge/Embeds.php

    r3777980 r3791202  
    9292        public function render( int $id, bool $title = true ): string {
    9393                $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                }
    9497                if ( ! $post instanceof \WP_Post || Articles::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status || ! Articles::can_read( $id ) || isset( self::$rendering[ $id ] ) ) {
    9598                        return '';
  • cliedesk/tags/1.2.4/src/Modules/Knowledge/HelpCenter.php

    r3777980 r3791202  
    3636                add_filter( 'template_include', array( $this, 'classic_template' ), 20 );
    3737                add_action( 'wp_enqueue_scripts', array( $this, 'assets' ) );
     38                add_action( 'template_redirect', array( self::class, 'cache_policy' ), 0 );
    3839                add_filter( 'body_class', array( $this, 'body_class' ) );
    3940                // KB-37: the help-center search on any page (the block works too).
    … …  
    4647        public static function is_help(): bool {
    4748                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();
    4865        }
    4966
  • cliedesk/tags/1.2.4/src/Modules/Knowledge/Lifecycle.php

    r3747777 r3791202  
    142142                }
    143143                status_header( 410 );
    144                 nocache_headers();
     144                \Cliedesk\Infrastructure\Http\NoCache::page();
    145145        }
    146146
  • cliedesk/tags/1.2.4/src/Modules/Knowledge/Redirects.php

    r3747777 r3791202  
    143143                $wp_query->query( array( 'post_type' => Articles::POST_TYPE ) );
    144144                status_header( 404 );
    145                 nocache_headers();
     145                \Cliedesk\Infrastructure\Http\NoCache::page();
    146146        }
    147147
  • cliedesk/tags/1.2.4/src/Modules/Portal/PortalModule.php

    r3789063 r3791202  
    153153                        'template_redirect',
    154154                        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() ) {
    157160                                        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();
    162161                                }
    163162                                self::remember_language();
  • cliedesk/tags/1.2.4/src/Modules/Requests/RequestPage.php

    r3790823 r3791202  
    8282                $type    = sanitize_key( (string) get_query_var( 'cliedesk_request_type' ) );
    8383                $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();
    8585                header( 'X-Robots-Tag: noindex' );
    8686                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  
    141141                if ( null === $config ) {
    142142                        status_header( 404 );
    143                         nocache_headers();
     143                        \Cliedesk\Infrastructure\Http\NoCache::page();
    144144                        exit;
    145145                }
    146                 nocache_headers();
     146                \Cliedesk\Infrastructure\Http\NoCache::page();
    147147                header( 'X-Robots-Tag: noindex' );
    148148                // 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  
    112112         */
    113113        public function identity(): void {
    114                 nocache_headers();
     114                \Cliedesk\Infrastructure\Http\NoCache::page();
    115115                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.
    116116        }
  • cliedesk/tags/1.2.4/src/Modules/Widget/WidgetModule.php

    r3787995 r3791202  
    936936                        return;
    937937                }
     938                // The page carries the public config: a cached copy is refreshed when the settings change.
     939                \Cliedesk\Infrastructure\Http\NoCache::tag_public();
    938940                wp_enqueue_script(
    939941                        'cliedesk-widget',
    … …  
    953955                                        return $tag;
    954956                                }
    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 );
    957960                        },
    958961                        10,
  • cliedesk/tags/1.2.4/src/Modules/Workspace/Actions/ProductUpdate.php

    r3747777 r3791202  
    113113                if ( array() !== $columns ) {
    114114                        $version = $this->ws->products->update( (int) $row['id'], $columns, $version );
     115                        \Cliedesk\Infrastructure\Http\NoCache::purge_public(); // Cached pages carry the product's address.
    115116                }
    116117                if ( array_key_exists( 'mappings', $input ) ) {
  • cliedesk/tags/1.2.4/src/Rest/RestServer.php

    r3790823 r3791202  
    1919use Cliedesk\Infrastructure\ChangeLog;
    2020use Cliedesk\Infrastructure\Ephemeral;
     21use Cliedesk\Infrastructure\Http\NoCache;
    2122use Cliedesk\Infrastructure\Jobs\Kick;
    2223use Cliedesk\Infrastructure\RequestId;
    … …  
    7879                add_filter( 'rest_pre_dispatch', array( $this, 'complete_routes' ), 0, 3 );
    7980                add_filter( 'rest_pre_dispatch', array( $this, 'guard' ), 10, 3 );
     81                add_filter( 'rest_pre_dispatch', array( $this, 'never_cache' ), 0, 3 );
    8082                add_filter( 'rest_post_dispatch', array( $this, 'headers' ), 10, 3 );
    8183                add_filter( 'rest_index', array( $this, 'trim_index' ) );
    … …  
    273275
    274276        /**
    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.
    276294         *
    277295         * @param \WP_HTTP_Response $response Response.
    … …  
    281299         */
    282300        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 ) ) {
    284309                        $response->header( 'X-Request-Id', RequestId::get() );
    285310                        $response->header( 'Cache-Control', 'no-store, private' );
  • cliedesk/tags/1.2.4/vendor/autoload.php

    r3790823 r3791202  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef::getLoader();
     25return ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f::getLoader();
  • cliedesk/tags/1.2.4/vendor/composer/autoload_real.php

    r3790823 r3791202  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef
     5class ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f
    66{
    77    private static $loader;
    … …  
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::getInitializer($loader));
    3333
    3434        $loader->setClassMapAuthoritative(true);
  • cliedesk/tags/1.2.4/vendor/composer/autoload_static.php

    r3790823 r3791202  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef
     7class ComposerStaticInit508f8c01434f52142bdea5cdb512e43f
    88{
    99    public static $classMap = array (
    … …  
    1414    {
    1515        return \Closure::bind(function () use ($loader) {
    16             $loader->classMap = ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef::$classMap;
     16            $loader->classMap = ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::$classMap;
    1717
    1818        }, null, ClassLoader::class);
  • cliedesk/trunk/changelog.txt

    r3790823 r3791202  
    22
    33Full 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.
    411
    512= 1.2.3 =
  • cliedesk/trunk/cliedesk.php

    r3790823 r3791202  
    44 * Plugin URI:        https://cliedesk.com/
    55 * 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.3
     6 * Version:           1.2.4
    77 * Requires at least: 7.0
    88 * Requires PHP:      8.1
    … …  
    1919defined( 'ABSPATH' ) || exit;
    2020
    21 define( 'CLIEDESK_VERSION', '1.2.3' );
     21define( 'CLIEDESK_VERSION', '1.2.4' );
    2222define( 'CLIEDESK_FILE', __FILE__ );
    2323define( 'CLIEDESK_DIR', __DIR__ . '/' );
  • cliedesk/trunk/readme.txt

    r3790823 r3791202  
    66Tested up to: 7.1
    77Requires PHP: 8.1
    8 Stable tag: 1.2.3
     8Stable tag: 1.2.4
    99License: GPL-2.0-or-later
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html
    … …  
    149149== Changelog ==
    150150
    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.
    155156
    156157Full notes and older entries are in changelog.txt.
    … …  
    158159== Upgrade Notice ==
    159160
     161= 1.2.4 =
     162Security update for sites using LiteSpeed Cache: private chat data could be served to other visitors, and chat replies did not arrive. Please update.
     163
    160164= 1.2.3 =
    161165A 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  
    167167                        return;
    168168                }
    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();
    176170                header( 'Vary: Cookie', false );
    177171                // The app is never framed by another site, never sniffed as another type, and asks only for the microphone
    … …  
    182176                header( 'Referrer-Policy: strict-origin-when-cross-origin' );
    183177                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.
    185178        }
    186179
  • cliedesk/trunk/src/Core/Plugin.php

    r3790823 r3791202  
    155155                add_action( 'init', array( self::class, 'register_modules' ), 1 );
    156156                add_action( 'init', array( self::class, 'maybe_upgrade' ), 2 );
     157                \Cliedesk\Infrastructure\Http\NoCache::hooks();
    157158                add_action( Installer::MIGRATE_HOOK, array( Installer::class, 'run_background_batch' ) );
    158159                add_action( Installer::NETWORK_INSTALL_HOOK, array( Installer::class, 'run_network_install' ) );
    … …  
    490491                        Installer::seed( self::container()->get( Db::class ), self::container()->get( Clock::class ) );
    491492                        Installer::add_capabilities();
     493                        // Answers cached by an earlier version would otherwise be served until they expire.
     494                        \Cliedesk\Infrastructure\Http\NoCache::purge_all();
    492495                        self::update_core_option(
    493496                                array(
  • cliedesk/trunk/src/Infrastructure/Files/FileLinks.php

    r3777980 r3791202  
    178178                );
    179179                // phpcs:enable WordPress.Security.NonceVerification.Recommended
    180                 nocache_headers();
     180                \Cliedesk\Infrastructure\Http\NoCache::page();
    181181                header( 'X-Content-Type-Options: nosniff' );
    182182                header( 'Referrer-Policy: no-referrer' );
  • cliedesk/trunk/src/Modules/Commerce/Account/EmailChange.php

    r3787995 r3791202  
    231231                $out    = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token );
    232232                status_header( $out['status'] );
    233                 nocache_headers();
     233                \Cliedesk\Infrastructure\Http\NoCache::page();
    234234                header( 'Content-Type: text/html; charset=utf-8' );
    235235                header( 'X-Robots-Tag: noindex' );
  • cliedesk/trunk/src/Modules/Core/ModuleSwitches.php

    r3787995 r3791202  
    146146                $stopped = $this->modules->resolve_off( $off );
    147147                update_option( ModuleRegistry::OFF_OPTION, $off, true );
     148                \Cliedesk\Infrastructure\Http\NoCache::purge_public();
    148149                // Pages of modules that stop or start (the portal address) change the rewrite rules on the next request.
    149150                $this->router?->request_flush();
  • cliedesk/trunk/src/Modules/Crm/Unsubscribe.php

    r3747777 r3791202  
    101101                $out    = $this->respond( 'POST' === $method ? 'POST' : 'GET', $token );
    102102                status_header( $out['status'] );
    103                 nocache_headers();
     103                \Cliedesk\Infrastructure\Http\NoCache::page();
    104104                header( 'Content-Type: text/html; charset=utf-8' );
    105105                header( 'X-Robots-Tag: noindex' );
  • cliedesk/trunk/src/Modules/Csat/CsatPage.php

    r3747777 r3791202  
    4545                }
    4646                $response = $this->surveys->by_token( $token );
    47                 nocache_headers();
     47                \Cliedesk\Infrastructure\Http\NoCache::page();
    4848                header( 'X-Robots-Tag: noindex, nofollow' );
    4949                header( 'Referrer-Policy: no-referrer' );
  • cliedesk/trunk/src/Modules/Knowledge/Embeds.php

    r3777980 r3791202  
    9292        public function render( int $id, bool $title = true ): string {
    9393                $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                }
    9497                if ( ! $post instanceof \WP_Post || Articles::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status || ! Articles::can_read( $id ) || isset( self::$rendering[ $id ] ) ) {
    9598                        return '';
  • cliedesk/trunk/src/Modules/Knowledge/HelpCenter.php

    r3777980 r3791202  
    3636                add_filter( 'template_include', array( $this, 'classic_template' ), 20 );
    3737                add_action( 'wp_enqueue_scripts', array( $this, 'assets' ) );
     38                add_action( 'template_redirect', array( self::class, 'cache_policy' ), 0 );
    3839                add_filter( 'body_class', array( $this, 'body_class' ) );
    3940                // KB-37: the help-center search on any page (the block works too).
    … …  
    4647        public static function is_help(): bool {
    4748                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();
    4865        }
    4966
  • cliedesk/trunk/src/Modules/Knowledge/Lifecycle.php

    r3747777 r3791202  
    142142                }
    143143                status_header( 410 );
    144                 nocache_headers();
     144                \Cliedesk\Infrastructure\Http\NoCache::page();
    145145        }
    146146
  • cliedesk/trunk/src/Modules/Knowledge/Redirects.php

    r3747777 r3791202  
    143143                $wp_query->query( array( 'post_type' => Articles::POST_TYPE ) );
    144144                status_header( 404 );
    145                 nocache_headers();
     145                \Cliedesk\Infrastructure\Http\NoCache::page();
    146146        }
    147147
  • cliedesk/trunk/src/Modules/Portal/PortalModule.php

    r3789063 r3791202  
    153153                        'template_redirect',
    154154                        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() ) {
    157160                                        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();
    162161                                }
    163162                                self::remember_language();
  • cliedesk/trunk/src/Modules/Requests/RequestPage.php

    r3790823 r3791202  
    8282                $type    = sanitize_key( (string) get_query_var( 'cliedesk_request_type' ) );
    8383                $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();
    8585                header( 'X-Robots-Tag: noindex' );
    8686                header( 'Content-Security-Policy: ' . self::frame_ancestors( (string) $this->settings->get( 'requests.embed_origins' ) ) );
  • cliedesk/trunk/src/Modules/Widget/ChatPage.php

    r3790823 r3791202  
    141141                if ( null === $config ) {
    142142                        status_header( 404 );
    143                         nocache_headers();
     143                        \Cliedesk\Infrastructure\Http\NoCache::page();
    144144                        exit;
    145145                }
    146                 nocache_headers();
     146                \Cliedesk\Infrastructure\Http\NoCache::page();
    147147                header( 'X-Robots-Tag: noindex' );
    148148                // 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  
    112112         */
    113113        public function identity(): void {
    114                 nocache_headers();
     114                \Cliedesk\Infrastructure\Http\NoCache::page();
    115115                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.
    116116        }
  • cliedesk/trunk/src/Modules/Widget/WidgetModule.php

    r3787995 r3791202  
    936936                        return;
    937937                }
     938                // The page carries the public config: a cached copy is refreshed when the settings change.
     939                \Cliedesk\Infrastructure\Http\NoCache::tag_public();
    938940                wp_enqueue_script(
    939941                        'cliedesk-widget',
    … …  
    953955                                        return $tag;
    954956                                }
    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 );
    957960                        },
    958961                        10,
  • cliedesk/trunk/src/Modules/Workspace/Actions/ProductUpdate.php

    r3747777 r3791202  
    113113                if ( array() !== $columns ) {
    114114                        $version = $this->ws->products->update( (int) $row['id'], $columns, $version );
     115                        \Cliedesk\Infrastructure\Http\NoCache::purge_public(); // Cached pages carry the product's address.
    115116                }
    116117                if ( array_key_exists( 'mappings', $input ) ) {
  • cliedesk/trunk/src/Rest/RestServer.php

    r3790823 r3791202  
    1919use Cliedesk\Infrastructure\ChangeLog;
    2020use Cliedesk\Infrastructure\Ephemeral;
     21use Cliedesk\Infrastructure\Http\NoCache;
    2122use Cliedesk\Infrastructure\Jobs\Kick;
    2223use Cliedesk\Infrastructure\RequestId;
    … …  
    7879                add_filter( 'rest_pre_dispatch', array( $this, 'complete_routes' ), 0, 3 );
    7980                add_filter( 'rest_pre_dispatch', array( $this, 'guard' ), 10, 3 );
     81                add_filter( 'rest_pre_dispatch', array( $this, 'never_cache' ), 0, 3 );
    8082                add_filter( 'rest_post_dispatch', array( $this, 'headers' ), 10, 3 );
    8183                add_filter( 'rest_index', array( $this, 'trim_index' ) );
    … …  
    273275
    274276        /**
    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.
    276294         *
    277295         * @param \WP_HTTP_Response $response Response.
    … …  
    281299         */
    282300        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 ) ) {
    284309                        $response->header( 'X-Request-Id', RequestId::get() );
    285310                        $response->header( 'Cache-Control', 'no-store, private' );
  • cliedesk/trunk/vendor/autoload.php

    r3790823 r3791202  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef::getLoader();
     25return ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f::getLoader();
  • cliedesk/trunk/vendor/composer/autoload_real.php

    r3790823 r3791202  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef
     5class ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f
    66{
    77    private static $loader;
    … …  
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInit5ca9f3f659c1c103c5481660e5e322ef', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit508f8c01434f52142bdea5cdb512e43f', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::getInitializer($loader));
    3333
    3434        $loader->setClassMapAuthoritative(true);
  • cliedesk/trunk/vendor/composer/autoload_static.php

    r3790823 r3791202  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef
     7class ComposerStaticInit508f8c01434f52142bdea5cdb512e43f
    88{
    99    public static $classMap = array (
    … …  
    1414    {
    1515        return \Closure::bind(function () use ($loader) {
    16             $loader->classMap = ComposerStaticInit5ca9f3f659c1c103c5481660e5e322ef::$classMap;
     16            $loader->classMap = ComposerStaticInit508f8c01434f52142bdea5cdb512e43f::$classMap;
    1717
    1818        }, null, ClassLoader::class);
Note: See TracChangeset for help on using the changeset viewer.