diff --git a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php index ba8c7f45b49c3..f0ba4fc2207cb 100644 --- a/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php +++ b/lib/private/AppFramework/Middleware/Security/BruteForceMiddleware.php @@ -41,7 +41,6 @@ use OCP\IRequest; use OCP\Security\Bruteforce\MaxDelayReached; use Psr\Log\LoggerInterface; -use ReflectionMethod; /** * Class BruteForceMiddleware performs the bruteforce protection for controllers @@ -69,15 +68,11 @@ public function beforeController($controller, $methodName) { $action = $this->reflector->getAnnotationParameter('BruteForceProtection', 'action'); $this->throttler->sleepDelayOrThrowOnMax($this->request->getRemoteAddress(), $action); } else { - $reflectionMethod = new ReflectionMethod($controller, $methodName); - $attributes = $reflectionMethod->getAttributes(BruteForceProtection::class); + $attributes = $this->reflector->getAttributes(BruteForceProtection::class); if (!empty($attributes)) { $remoteAddress = $this->request->getRemoteAddress(); - - foreach ($attributes as $attribute) { - /** @var BruteForceProtection $protection */ - $protection = $attribute->newInstance(); + foreach ($attributes as $protection) { $action = $protection->getAction(); $this->throttler->sleepDelayOrThrowOnMax($remoteAddress, $action); } @@ -96,16 +91,13 @@ public function afterController($controller, $methodName, Response $response) { $this->throttler->sleepDelay($ip, $action); $this->throttler->registerAttempt($action, $ip, $response->getThrottleMetadata()); } else { - $reflectionMethod = new ReflectionMethod($controller, $methodName); - $attributes = $reflectionMethod->getAttributes(BruteForceProtection::class); + $attributes = $this->reflector->getAttributes(BruteForceProtection::class); if (!empty($attributes)) { $ip = $this->request->getRemoteAddress(); $metaData = $response->getThrottleMetadata(); - foreach ($attributes as $attribute) { - /** @var BruteForceProtection $protection */ - $protection = $attribute->newInstance(); + foreach ($attributes as $protection) { $action = $protection->getAction(); if (!isset($metaData['action']) || $metaData['action'] === $action) { diff --git a/lib/private/AppFramework/Middleware/SessionMiddleware.php b/lib/private/AppFramework/Middleware/SessionMiddleware.php index 39f85915901d6..01c309e6b499b 100644 --- a/lib/private/AppFramework/Middleware/SessionMiddleware.php +++ b/lib/private/AppFramework/Middleware/SessionMiddleware.php @@ -34,7 +34,6 @@ use OCP\AppFramework\Http\Response; use OCP\AppFramework\Middleware; use OCP\ISession; -use ReflectionMethod; class SessionMiddleware extends Middleware { /** @var ControllerMethodReflector */ @@ -63,8 +62,7 @@ public function beforeController($controller, $methodName) { return; } - $reflectionMethod = new ReflectionMethod($controller, $methodName); - $hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class)); + $hasAttribute = !empty($this->reflector->getAttributes(UseSession::class)); if ($hasAttribute) { $this->session->reopen(); } @@ -86,8 +84,7 @@ public function afterController($controller, $methodName, Response $response) { return $response; } - $reflectionMethod = new ReflectionMethod($controller, $methodName); - $hasAttribute = !empty($reflectionMethod->getAttributes(UseSession::class)); + $hasAttribute = !empty($this->reflector->getAttributes(UseSession::class)); if ($hasAttribute) { $this->session->close(); } diff --git a/lib/private/AppFramework/Utility/ControllerMethodReflector.php b/lib/private/AppFramework/Utility/ControllerMethodReflector.php index b76b3c33c42a9..7f3cdbfac8f42 100644 --- a/lib/private/AppFramework/Utility/ControllerMethodReflector.php +++ b/lib/private/AppFramework/Utility/ControllerMethodReflector.php @@ -33,12 +33,15 @@ */ namespace OC\AppFramework\Utility; +use Attribute; use OCP\AppFramework\Utility\IControllerMethodReflector; /** * Reads and parses annotations from doc comments */ class ControllerMethodReflector implements IControllerMethodReflector { + + protected ?\ReflectionMethod $reflection; public $annotations = []; private $types = []; private $parameters = []; @@ -48,8 +51,8 @@ class ControllerMethodReflector implements IControllerMethodReflector { * @param string $method the method which we want to inspect */ public function reflect($object, string $method) { - $reflection = new \ReflectionMethod($object, $method); - $docs = $reflection->getDocComment(); + $this->reflection = new \ReflectionMethod($object, $method); + $docs = $this->reflection->getDocComment(); if ($docs !== false) { // extract everything prefixed by @ and first letter uppercase @@ -76,7 +79,7 @@ public function reflect($object, string $method) { $this->types = array_combine($matches['var'], $matches['type']); } - foreach ($reflection->getParameters() as $param) { + foreach ($this->reflection->getParameters() as $param) { // extract type information from PHP 7 scalar types and prefer them over phpdoc annotations $type = $param->getType(); if ($type instanceof \ReflectionNamedType) { @@ -138,4 +141,18 @@ public function getAnnotationParameter(string $name, string $key): string { return ''; } + + /** + * @template T of Attribute + * @param class-string $class + * @return T[] + */ + public function getAttributes(string $class): array { + $attributes = $this->reflection->getAttributes($class); + $return = []; + foreach ($attributes as $attribute) { + $return[] = $attribute->newInstance(); + } + return $return; + } } diff --git a/lib/public/AppFramework/Utility/IControllerMethodReflector.php b/lib/public/AppFramework/Utility/IControllerMethodReflector.php index a091c8b37077c..a349b765e6676 100644 --- a/lib/public/AppFramework/Utility/IControllerMethodReflector.php +++ b/lib/public/AppFramework/Utility/IControllerMethodReflector.php @@ -27,6 +27,8 @@ */ namespace OCP\AppFramework\Utility; +use Attribute; + /** * Interface ControllerMethodReflector * @@ -75,4 +77,12 @@ public function getParameters(): array; * @see https://help.nextcloud.com/t/how-should-we-use-php8-attributes/104278 */ public function hasAnnotation(string $name): bool; + + /** + * @template T of Attribute + * @param class-string $class + * @return T[] + * @since 27.0.0 + */ + public function getAttributes(string $class): array; }