Properly handle `NamedUserException` thrown by PSR controllers
authorAlexander Ebert <ebert@woltlab.com>
Sat, 23 Dec 2023 17:02:05 +0000 (18:02 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 23 Dec 2023 17:02:05 +0000 (18:02 +0100)
See https://www.woltlab.com/community/thread/303681/

wcfsetup/install/files/lib/http/error/OperationNotPermittedHandler.class.php [new file with mode: 0644]
wcfsetup/install/files/lib/http/middleware/HandleExceptions.class.php

diff --git a/wcfsetup/install/files/lib/http/error/OperationNotPermittedHandler.class.php b/wcfsetup/install/files/lib/http/error/OperationNotPermittedHandler.class.php
new file mode 100644 (file)
index 0000000..e979b54
--- /dev/null
@@ -0,0 +1,66 @@
+<?php
+
+namespace wcf\http\error;
+
+use Laminas\Diactoros\Response\HtmlResponse;
+use Laminas\Diactoros\Response\JsonResponse;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use Psr\Http\Server\RequestHandlerInterface;
+use wcf\http\Helper;
+use wcf\system\box\BoxHandler;
+use wcf\system\notice\NoticeHandler;
+use wcf\system\request\RequestHandler;
+use wcf\system\session\SessionHandler;
+use wcf\system\WCF;
+
+/**
+ * Returns an "Operation Not Permitted" response.
+ *
+ * @author Alexander Ebert
+ * @copyright 2001-2023 WoltLab GmbH
+ * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @since 6.0
+ */
+final class OperationNotPermittedHandler implements RequestHandlerInterface
+{
+    private const STATUS_CODE = 403;
+
+    public function handle(ServerRequestInterface $request): ResponseInterface
+    {
+        $errorDetail = ErrorDetail::fromRequest($request);
+        $message = $errorDetail?->getMessage() ?? WCF::getLanguage()->getDynamicVariable('wcf.global.error.title');
+
+        if (!RequestHandler::getInstance()->isACPRequest()) {
+            BoxHandler::disablePageLayout();
+            NoticeHandler::disableNotices();
+        }
+        SessionHandler::getInstance()->disableTracking();
+
+        $preferredType = Helper::getPreferredContentType($request, [
+            'application/json',
+            'text/html',
+        ]);
+
+        return match ($preferredType) {
+            'application/json' => new JsonResponse(
+                [
+                    'message' => $message,
+                    'exception' => \ENABLE_DEBUG_MODE ? $errorDetail?->getThrowable()?->__toString() : null,
+                ],
+                self::STATUS_CODE,
+                [],
+                \JSON_PRETTY_PRINT
+            ),
+            'text/html' => new HtmlResponse(
+                (new HtmlErrorRenderer())->render(
+                    WCF::getLanguage()->getDynamicVariable('wcf.global.error.title'),
+                    $message,
+                    $errorDetail?->getThrowable(),
+                    !WCF::getUser()->userID,
+                ),
+                self::STATUS_CODE
+            ),
+        };
+    }
+}
index 05a03373316496c15d3dcf6130426d2a1b3eeca8..c5f8a34259765fec5d1183338e268a1054e3d236 100644 (file)
@@ -8,10 +8,12 @@ use Psr\Http\Server\MiddlewareInterface;
 use Psr\Http\Server\RequestHandlerInterface;
 use wcf\http\error\ErrorDetail;
 use wcf\http\error\NotFoundHandler;
+use wcf\http\error\OperationNotPermittedHandler;
 use wcf\http\error\PermissionDeniedHandler;
 use wcf\http\error\XsrfValidationFailedHandler;
 use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\InvalidSecurityTokenException;
+use wcf\system\exception\NamedUserException;
 use wcf\system\exception\PermissionDeniedException;
 
 /**
@@ -32,13 +34,15 @@ final class HandleExceptions implements MiddlewareInterface
     {
         try {
             return $handler->handle($request);
-        } catch (PermissionDeniedException | IllegalLinkException | InvalidSecurityTokenException $e) {
+        } catch (PermissionDeniedException | IllegalLinkException | InvalidSecurityTokenException | NamedUserException $e) {
             if ($e instanceof PermissionDeniedException) {
                 $handler = new PermissionDeniedHandler();
             } elseif ($e instanceof IllegalLinkException) {
                 $handler = new NotFoundHandler();
             } elseif ($e instanceof InvalidSecurityTokenException) {
                 $handler = new XsrfValidationFailedHandler();
+            } elseif ($e instanceof NamedUserException) {
+                $handler = new OperationNotPermittedHandler();
             } else {
                 throw new \LogicException('Unreachable');
             }