From 1e947c0ebbd86ed07c0b7227f3d96b1d74d22d75 Mon Sep 17 00:00:00 2001 From: hama Date: Mon, 15 Mar 2021 18:21:56 +0900 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=80=85=E3=81=AF=E3=83=A1?= =?UTF-8?q?=E3=83=B3=E3=83=86=E3=83=8A=E3=83=B3=E3=82=B9=E3=83=A2=E3=83=BC?= =?UTF-8?q?=E3=83=89=E3=82=92=E5=9B=9E=E9=81=BF=E5=8F=AF=E8=83=BD=E3=81=AB?= =?UTF-8?q?=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.php | 20 ++++-- .../Admin/Content/MaintenanceController.php | 6 +- .../EventListener/MaintenanceListener.php | 64 +++++++++++++++++++ src/Eccube/Service/SystemService.php | 57 ++++++++++++++--- 4 files changed, 126 insertions(+), 21 deletions(-) create mode 100644 src/Eccube/EventListener/MaintenanceListener.php diff --git a/index.php b/index.php index 103b4e62fd2..ec1f5db62c1 100644 --- a/index.php +++ b/index.php @@ -1,6 +1,7 @@ getBaseUrl()), ENT_QUOTES); - - header('HTTP/1.1 503 Service Temporarily Unavailable'); - require __DIR__.'/maintenance.php'; - return; + $maintenanceContents = file_get_contents($maintenanceFile); + $maintenanceToken = explode(':', $maintenanceContents)[1] ?? null; + $tokenInCookie = $request->cookies->get(SystemService::MAINTENANCE_TOKEN_KEY); + if ($tokenInCookie === null || $tokenInCookie !== $maintenanceToken) { + $locale = env('ECCUBE_LOCALE'); + $templateCode = env('ECCUBE_TEMPLATE_CODE'); + $baseUrl = \htmlspecialchars(\rawurldecode($request->getBaseUrl()), ENT_QUOTES); + + header('HTTP/1.1 503 Service Temporarily Unavailable'); + require __DIR__.'/maintenance.php'; + return; + } } } diff --git a/src/Eccube/Controller/Admin/Content/MaintenanceController.php b/src/Eccube/Controller/Admin/Content/MaintenanceController.php index 955ca9a5b52..8f46a2e7074 100644 --- a/src/Eccube/Controller/Admin/Content/MaintenanceController.php +++ b/src/Eccube/Controller/Admin/Content/MaintenanceController.php @@ -48,18 +48,16 @@ public function index(Request $request) if ($form->isSubmitted() && $form->isValid()) { $changeTo = $request->request->get('maintenance'); - $path = $this->container->getParameter('eccube_content_maintenance_file_path'); if ($isMaintenance === false && $changeTo == 'on') { // 現在メンテナンスモードではない かつ メンテナンスモードを有効 にした場合 // メンテナンスモードを有効にする - file_put_contents($path, null); - + $this->systemService->enableMaintenance('', true); $this->addSuccess('admin.content.maintenance_switch__on_message', 'admin'); } elseif ($isMaintenance && $changeTo == 'off') { // 現在メンテナンスモード かつ メンテナンスモードを無効 にした場合 // メンテナンスモードを無効にする - unlink($path); + $this->systemService->disableMaintenanceNow('', true); $this->addSuccess('admin.content.maintenance_switch__off_message', 'admin'); } diff --git a/src/Eccube/EventListener/MaintenanceListener.php b/src/Eccube/EventListener/MaintenanceListener.php new file mode 100644 index 00000000000..07554ef997a --- /dev/null +++ b/src/Eccube/EventListener/MaintenanceListener.php @@ -0,0 +1,64 @@ +requestContext = $requestContext; + $this->systemService = $systemService; + } + + public static function getSubscribedEvents() + { + return [ + KernelEvents::RESPONSE => ['onResponse'], + ]; + } + + public function onResponse(FilterResponseEvent $event) + { + $response = $event->getResponse(); + + if (!$this->systemService->isMaintenanceMode()) { + $response->headers->clearCookie(SystemService::MAINTENANCE_TOKEN_KEY); + return; + } + + $user = $this->requestContext->getCurrentUser(); + if ($user instanceof Entity\Member && $this->requestContext->isAdmin()) { + $cookie = new Cookie( + SystemService::MAINTENANCE_TOKEN_KEY, + $this->systemService->getMaintenanceToken() + ); + $response->headers->setCookie($cookie); + } + } +} diff --git a/src/Eccube/Service/SystemService.php b/src/Eccube/Service/SystemService.php index b338283bbae..354c6109fbf 100644 --- a/src/Eccube/Service/SystemService.php +++ b/src/Eccube/Service/SystemService.php @@ -14,14 +14,21 @@ namespace Eccube\Service; use Doctrine\ORM\EntityManagerInterface; +use Eccube\Util\StringUtil; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\Event\PostResponseEvent; +use function explode; +use function file_exists; +use function file_get_contents; +use function file_put_contents; +use function unlink; class SystemService implements EventSubscriberInterface { + const MAINTENANCE_TOKEN_KEY = 'maintenance_token'; const AUTO_MAINTENANCE = 'auto_maintenance'; const AUTO_MAINTENANCE_UPDATE = 'auto_maintenance_update'; @@ -140,20 +147,26 @@ public function getMemoryLimit() * * @param bool $isEnable * @param string $mode + * @param bool $force */ - public function switchMaintenance($isEnable = false, $mode = self::AUTO_MAINTENANCE) + public function switchMaintenance($isEnable = false, $mode = self::AUTO_MAINTENANCE, bool $force = false): void { - $isMaintenanceMode = $this->isMaintenanceMode(); - $path = $this->container->getParameter('eccube_content_maintenance_file_path'); + if ($isEnable) { + $this->enableMaintenance($mode, $force); + } else { + $this->disableMaintenanceNow($mode, $force); + } + } - if ($isEnable && $isMaintenanceMode === false) { - file_put_contents($path, $mode); - } elseif ($isEnable === false && $isMaintenanceMode) { - $contents = file_get_contents($path); - if ($contents == $mode) { - unlink($path); - } + public function getMaintenanceToken(): ?string + { + $path = $this->container->getParameter('eccube_content_maintenance_file_path'); + if (!file_exists($path)) { + return null; } + + $contents = file_get_contents($path); + return explode(':', $contents)[1] ?? null; } /** @@ -168,6 +181,15 @@ public function disableMaintenanceEvent(PostResponseEvent $event) } } + public function enableMaintenance($mode = self::AUTO_MAINTENANCE, bool $force = false): void + { + if ($force || !$this->isMaintenanceMode()) { + $path = $this->container->getParameter('eccube_content_maintenance_file_path'); + $token = StringUtil::random(32); + file_put_contents($path, "{$mode}:{$token}"); + } + } + /** * メンテナンスモードを解除する * @@ -181,6 +203,21 @@ public function disableMaintenance($mode = self::AUTO_MAINTENANCE) $this->maintenanceMode = $mode; } + public function disableMaintenanceNow($mode = self::AUTO_MAINTENANCE, bool $force = false): void + { + if (!$this->isMaintenanceMode()) { + return; + } + + $path = $this->container->getParameter('eccube_content_maintenance_file_path'); + $contents = file_get_contents($path); + $currentMode = explode(':', $contents)[0] ?? null; + + if ($force || $currentMode === $mode) { + unlink($path); + } + } + /** * メンテナンスモードの状態を判定する *