Skip to content

Commit 9f42a17

Browse files
committed
refactor: Move hasAnnotationOrAttribute to MiddlewareUtils
Signed-off-by: Carl Schwan <[email protected]>
1 parent 8f2eadb commit 9f42a17

File tree

15 files changed

+192
-329
lines changed

15 files changed

+192
-329
lines changed

build/psalm-baseline.xml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3324,13 +3324,6 @@
33243324
</DeprecatedMethod>
33253325
</file>
33263326
<file src="core/Middleware/TwoFactorMiddleware.php">
3327-
<DeprecatedInterface>
3328-
<code><![CDATA[private]]></code>
3329-
</DeprecatedInterface>
3330-
<DeprecatedMethod>
3331-
<code><![CDATA[hasAnnotation]]></code>
3332-
<code><![CDATA[hasAnnotation]]></code>
3333-
</DeprecatedMethod>
33343327
<NoInterfaceProperties>
33353328
<code><![CDATA[$this->request->server]]></code>
33363329
</NoInterfaceProperties>

core/Middleware/TwoFactorMiddleware.php

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
use Exception;
1313
use OC\AppFramework\Http\Attributes\TwoFactorSetUpDoneRequired;
14+
use OC\AppFramework\Middleware\MiddlewareUtils;
1415
use OC\Authentication\Exceptions\TwoFactorAuthRequiredException;
1516
use OC\Authentication\Exceptions\UserAlreadyLoggedInException;
1617
use OC\Authentication\TwoFactorAuth\Manager;
@@ -22,13 +23,11 @@
2223
use OCP\AppFramework\Http\Attribute\NoTwoFactorRequired;
2324
use OCP\AppFramework\Http\RedirectResponse;
2425
use OCP\AppFramework\Middleware;
25-
use OCP\AppFramework\Utility\IControllerMethodReflector;
2626
use OCP\Authentication\TwoFactorAuth\ALoginSetupController;
2727
use OCP\IRequest;
2828
use OCP\ISession;
2929
use OCP\IURLGenerator;
3030
use OCP\IUser;
31-
use Psr\Log\LoggerInterface;
3231
use ReflectionMethod;
3332

3433
class TwoFactorMiddleware extends Middleware {
@@ -37,9 +36,8 @@ public function __construct(
3736
private Session $userSession,
3837
private ISession $session,
3938
private IURLGenerator $urlGenerator,
40-
private IControllerMethodReflector $reflector,
39+
private MiddlewareUtils $middlewareUtils,
4140
private IRequest $request,
42-
private LoggerInterface $logger,
4341
) {
4442
}
4543

@@ -50,7 +48,7 @@ public function __construct(
5048
public function beforeController($controller, $methodName) {
5149
$reflectionMethod = new ReflectionMethod($controller, $methodName);
5250

53-
if ($this->hasAnnotationOrAttribute($reflectionMethod, 'NoTwoFactorRequired', NoTwoFactorRequired::class)) {
51+
if ($this->middlewareUtils->hasAnnotationOrAttribute($reflectionMethod, 'NoTwoFactorRequired', NoTwoFactorRequired::class)) {
5452
// Route handler explicitly marked to work without finished 2FA are
5553
// not blocked
5654
return;
@@ -137,26 +135,4 @@ public function afterException($controller, $methodName, Exception $exception) {
137135

138136
throw $exception;
139137
}
140-
141-
142-
/**
143-
* @template T
144-
*
145-
* @param ReflectionMethod $reflectionMethod
146-
* @param ?string $annotationName
147-
* @param class-string<T> $attributeClass
148-
* @return boolean
149-
*/
150-
protected function hasAnnotationOrAttribute(ReflectionMethod $reflectionMethod, ?string $annotationName, string $attributeClass): bool {
151-
if (!empty($reflectionMethod->getAttributes($attributeClass))) {
152-
return true;
153-
}
154-
155-
if ($annotationName && $this->reflector->hasAnnotation($annotationName)) {
156-
$this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
157-
return true;
158-
}
159-
160-
return false;
161-
}
162138
}

lib/composer/composer/LICENSE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
Copyright (c) Nils Adermann, Jordi Boggiano
23

34
Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -17,3 +18,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1718
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
1819
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
1920
THE SOFTWARE.
21+

lib/composer/composer/autoload_classmap.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,6 +1064,7 @@
10641064
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
10651065
'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
10661066
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => $baseDir . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
1067+
'OC\\AppFramework\\Middleware\\MiddlewareUtils' => $baseDir . '/lib/private/AppFramework/Middleware/MiddlewareUtils.php',
10671068
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
10681069
'OC\\AppFramework\\Middleware\\OCSMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
10691070
'OC\\AppFramework\\Middleware\\PublicShare\\Exceptions\\NeedAuthenticationException' => $baseDir . '/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php',

lib/composer/composer/autoload_static.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1105,6 +1105,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
11051105
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
11061106
'OC\\AppFramework\\Middleware\\FlowV2EphemeralSessionsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/FlowV2EphemeralSessionsMiddleware.php',
11071107
'OC\\AppFramework\\Middleware\\MiddlewareDispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/MiddlewareDispatcher.php',
1108+
'OC\\AppFramework\\Middleware\\MiddlewareUtils' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/MiddlewareUtils.php',
11081109
'OC\\AppFramework\\Middleware\\NotModifiedMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/NotModifiedMiddleware.php',
11091110
'OC\\AppFramework\\Middleware\\OCSMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/OCSMiddleware.php',
11101111
'OC\\AppFramework\\Middleware\\PublicShare\\Exceptions\\NeedAuthenticationException' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/PublicShare/Exceptions/NeedAuthenticationException.php',

lib/private/AppFramework/DependencyInjection/DIContainer.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use OC\AppFramework\Middleware\CompressionMiddleware;
1818
use OC\AppFramework\Middleware\FlowV2EphemeralSessionsMiddleware;
1919
use OC\AppFramework\Middleware\MiddlewareDispatcher;
20+
use OC\AppFramework\Middleware\MiddlewareUtils;
2021
use OC\AppFramework\Middleware\NotModifiedMiddleware;
2122
use OC\AppFramework\Middleware\OCSMiddleware;
2223
use OC\AppFramework\Middleware\PublicShare\PublicShareMiddleware;
@@ -31,6 +32,7 @@
3132
use OC\AppFramework\Middleware\Security\SecurityMiddleware;
3233
use OC\AppFramework\Middleware\SessionMiddleware;
3334
use OC\AppFramework\ScopedPsrLogger;
35+
use OC\AppFramework\Utility\ControllerMethodReflector;
3436
use OC\AppFramework\Utility\SimpleContainer;
3537
use OC\Core\Middleware\TwoFactorMiddleware;
3638
use OC\Diagnostics\EventLogger;
@@ -44,7 +46,6 @@
4446
use OCP\AppFramework\QueryException;
4547
use OCP\AppFramework\Services\IAppConfig;
4648
use OCP\AppFramework\Services\IInitialState;
47-
use OCP\AppFramework\Utility\IControllerMethodReflector;
4849
use OCP\Files\AppData\IAppDataFactory;
4950
use OCP\Files\Folder;
5051
use OCP\Files\IAppData;
@@ -155,7 +156,7 @@ public function __construct(string $appName, array $urlParams = [], ?ServerConta
155156
return new Dispatcher(
156157
$c->get(Http::class),
157158
$c->get(MiddlewareDispatcher::class),
158-
$c->get(IControllerMethodReflector::class),
159+
$c->get(ControllerMethodReflector::class),
159160
$c->get(IRequest::class),
160161
$c->get(IConfig::class),
161162
$c->get(IDBConnection::class),
@@ -193,7 +194,7 @@ public function __construct(string $appName, array $urlParams = [], ?ServerConta
193194

194195
$securityMiddleware = new SecurityMiddleware(
195196
$c->get(IRequest::class),
196-
$c->get(IControllerMethodReflector::class),
197+
$c->get(MiddlewareUtils::class),
197198
$c->get(INavigationManager::class),
198199
$c->get(IURLGenerator::class),
199200
$c->get(LoggerInterface::class),

lib/private/AppFramework/Http/Dispatcher.php

Lines changed: 24 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -26,64 +26,22 @@
2626
* Class to dispatch the request to the middleware dispatcher
2727
*/
2828
class Dispatcher {
29-
/** @var MiddlewareDispatcher */
30-
private $middlewareDispatcher;
31-
32-
/** @var Http */
33-
private $protocol;
34-
35-
/** @var ControllerMethodReflector */
36-
private $reflector;
37-
38-
/** @var IRequest */
39-
private $request;
40-
41-
/** @var IConfig */
42-
private $config;
43-
44-
/** @var ConnectionAdapter */
45-
private $connection;
46-
47-
/** @var LoggerInterface */
48-
private $logger;
49-
50-
/** @var IEventLogger */
51-
private $eventLogger;
52-
53-
private ContainerInterface $appContainer;
54-
5529
/**
5630
* @param Http $protocol the http protocol with contains all status headers
5731
* @param MiddlewareDispatcher $middlewareDispatcher the dispatcher which
5832
* runs the middleware
59-
* @param ControllerMethodReflector $reflector the reflector that is used to inject
60-
* the arguments for the controller
61-
* @param IRequest $request the incoming request
62-
* @param IConfig $config
63-
* @param ConnectionAdapter $connection
64-
* @param LoggerInterface $logger
65-
* @param IEventLogger $eventLogger
6633
*/
6734
public function __construct(
68-
Http $protocol,
69-
MiddlewareDispatcher $middlewareDispatcher,
70-
ControllerMethodReflector $reflector,
71-
IRequest $request,
72-
IConfig $config,
73-
ConnectionAdapter $connection,
74-
LoggerInterface $logger,
75-
IEventLogger $eventLogger,
76-
ContainerInterface $appContainer,
35+
private readonly Http $protocol,
36+
private readonly MiddlewareDispatcher $middlewareDispatcher,
37+
private readonly ControllerMethodReflector $reflector,
38+
private readonly IRequest $request,
39+
private readonly IConfig $config,
40+
private readonly ConnectionAdapter $connection,
41+
private readonly LoggerInterface $logger,
42+
private readonly IEventLogger $eventLogger,
43+
private readonly ContainerInterface $appContainer,
7744
) {
78-
$this->protocol = $protocol;
79-
$this->middlewareDispatcher = $middlewareDispatcher;
80-
$this->reflector = $reflector;
81-
$this->request = $request;
82-
$this->config = $config;
83-
$this->connection = $connection;
84-
$this->logger = $logger;
85-
$this->eventLogger = $eventLogger;
86-
$this->appContainer = $appContainer;
8745
}
8846

8947

@@ -92,16 +50,15 @@ public function __construct(
9250
* @param Controller $controller the controller which will be called
9351
* @param string $methodName the method name which will be called on
9452
* the controller
95-
* @return array $array[0] contains the http status header as a string,
96-
* $array[1] contains response headers as an array,
97-
* $array[2] contains response cookies as an array,
98-
* $array[3] contains the response output as a string,
99-
* $array[4] contains the response object
53+
* @return array{0: string, 1: array, 2: array, 3: string, 4: Response}
54+
* $array[0] contains the http status header as a string,
55+
* $array[1] contains response headers as an array,
56+
* $array[2] contains response cookies as an array,
57+
* $array[3] contains the response output as a string,
58+
* $array[4] contains the response object
10059
* @throws \Exception
10160
*/
10261
public function dispatch(Controller $controller, string $methodName): array {
103-
$out = [null, [], null];
104-
10562
try {
10663
// prefill reflector with everything that's needed for the
10764
// middlewares
@@ -156,15 +113,15 @@ public function dispatch(Controller $controller, string $methodName): array {
156113
$controller, $methodName, $response);
157114

158115
// depending on the cache object the headers need to be changed
159-
$out[0] = $this->protocol->getStatusHeader($response->getStatus());
160-
$out[1] = array_merge($response->getHeaders());
161-
$out[2] = $response->getCookies();
162-
$out[3] = $this->middlewareDispatcher->beforeOutput(
163-
$controller, $methodName, $response->render()
164-
);
165-
$out[4] = $response;
166-
167-
return $out;
116+
return [
117+
$this->protocol->getStatusHeader($response->getStatus()),
118+
array_merge($response->getHeaders()),
119+
$response->getCookies(),
120+
$this->middlewareDispatcher->beforeOutput(
121+
$controller, $methodName, $response->render()
122+
),
123+
$response,
124+
];
168125
}
169126

170127

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH
7+
* SPDX-FileContributor: Carl Schwan
8+
* SPDX-License-Identifier: AGPL-3.0-or-later
9+
*/
10+
11+
namespace OC\AppFramework\Middleware;
12+
13+
use OC\AppFramework\Utility\ControllerMethodReflector;
14+
use OCP\AppFramework\Http\Attribute\AuthorizedAdminSetting;
15+
use Psr\Log\LoggerInterface;
16+
use ReflectionMethod;
17+
18+
/**
19+
* Temporary helper to abstract IControllerMethodReflector and ReflectionMethod
20+
*/
21+
class MiddlewareUtils {
22+
public function __construct(
23+
private readonly ControllerMethodReflector $reflector,
24+
private readonly LoggerInterface $logger,
25+
) {
26+
}
27+
28+
/**
29+
* @template T
30+
*
31+
* @param ReflectionMethod $reflectionMethod
32+
* @param ?string $annotationName
33+
* @param class-string<T> $attributeClass
34+
* @return boolean
35+
*/
36+
public function hasAnnotationOrAttribute(ReflectionMethod $reflectionMethod, ?string $annotationName, string $attributeClass): bool {
37+
if (!empty($reflectionMethod->getAttributes($attributeClass))) {
38+
return true;
39+
}
40+
41+
if ($annotationName && $this->reflector->hasAnnotation($annotationName)) {
42+
$this->logger->debug($reflectionMethod->getDeclaringClass()->getName() . '::' . $reflectionMethod->getName() . ' uses the @' . $annotationName . ' annotation and should use the #[' . $attributeClass . '] attribute instead');
43+
return true;
44+
}
45+
46+
return false;
47+
}
48+
49+
/**
50+
* @param ReflectionMethod $reflectionMethod
51+
* @return string[]
52+
*/
53+
public function getAuthorizedAdminSettingClasses(ReflectionMethod $reflectionMethod): array {
54+
$classes = [];
55+
if ($this->reflector->hasAnnotation('AuthorizedAdminSetting')) {
56+
$classes = explode(';', $this->reflector->getAnnotationParameter('AuthorizedAdminSetting', 'settings'));
57+
}
58+
59+
$attributes = $reflectionMethod->getAttributes(AuthorizedAdminSetting::class);
60+
if (!empty($attributes)) {
61+
foreach ($attributes as $attribute) {
62+
/** @var AuthorizedAdminSetting $setting */
63+
$setting = $attribute->newInstance();
64+
$classes[] = $setting->getSettings();
65+
}
66+
}
67+
68+
return $classes;
69+
}
70+
}

0 commit comments

Comments
 (0)