From b678a25a3c1559e8e0dfea4d6afe3644c51ef800 Mon Sep 17 00:00:00 2001 From: "Fabian @ Blax Software" Date: Thu, 6 Aug 2026 10:42:34 +0200 Subject: [PATCH] feat(maintenance): per-message choke to freeze non-admins during platform maintenance Read the shared platform:maintenance DB-cache flag at controll_message (after auth resolves) and refuse every controller event for non-admins with {message, maintenance:true}, so a host app can run a deploy / write-locking migration without clients mutating state. Admins bypass to smoke-test. The key is hardcoded to match App\Support\Maintenance::CACHE_KEY and dodge the fork-child package-config-merge gap; cache reads are guarded so a hiccup can never wedge the socket. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/Websocket/Controller.php | 43 ++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Websocket/Controller.php b/src/Websocket/Controller.php index 15227f0..d0ff142 100644 --- a/src/Websocket/Controller.php +++ b/src/Websocket/Controller.php @@ -51,6 +51,34 @@ class Controller */ public function unboot(): void {} + /** + * Shared platform-maintenance flag, read from the same DB-cache key the host + * app writes via App\Support\Maintenance::CACHE_KEY. Hardcoded (not config) + * to dodge the fork-child package-config-merge gap, and wrapped so a cache + * hiccup can never wedge the socket. Keep the key string in sync with the app. + */ + protected static function maintenanceActive(): bool + { + try { + return (bool) cache()->get('platform:maintenance', false); + } catch (\Throwable) { + return false; + } + } + + protected static function maintenanceMessage(): string + { + try { + $message = cache()->get('platform:maintenance:message'); + } catch (\Throwable) { + $message = null; + } + + return is_string($message) && $message !== '' + ? $message + : 'We are performing scheduled maintenance and will be back shortly.'; + } + public static function controll_message( ConnectionInterface $connection, PrivateChannel|Channel|PresenceChannel $channel, @@ -133,6 +161,21 @@ class Controller } } + // Platform maintenance freeze. Once auth (incl. the self-heal above) + // has resolved the user, refuse every controller event for non-admins + // so a deploy/migration can run without clients mutating state. Admins + // bypass to smoke-test. The `auth` handshake + channel introspection + // are single-part events handled earlier, so a maintainer can still + // authenticate to obtain the bypass. + if (self::maintenanceActive() && ! ($connection->user?->is_admin ?? false)) { + $controller->error([ + 'message' => self::maintenanceMessage(), + 'maintenance' => true, + ]); + $controller->unboot(); + return; + } + if (! method_exists($controllerClass, $method)) { $controller->error('Event could not be handled'); $controller->unboot();