diff --git a/appinfo/info.xml b/appinfo/info.xml index c7b72b333..e9dd9bfac 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -20,6 +20,7 @@ https://www.arawa.fr/contact/ + diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 216b74427..b70790cb8 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -31,7 +31,6 @@ use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; -use OCP\AppFramework\Utility\IControllerMethodReflector; use OCP\IRequest; use OCP\IURLGenerator; @@ -52,7 +51,6 @@ public function register(IRegistrationContext $context): void { $context->registerService(IsSpaceAdminMiddleware::class, function ($c) { return new IsSpaceAdminMiddleware( - $c->query(IControllerMethodReflector::class), $c->query(IRequest::class), $c->query(UserService::class), $c->query(SpaceService::class) @@ -61,8 +59,6 @@ public function register(IRegistrationContext $context): void { $context->registerService(IsGeneralManagerMiddleware::class, function ($c) { return new IsGeneralManagerMiddleware( - $c->query(IControllerMethodReflector::class), - $c->query(IRequest::class), $c->query(UserService::class) ); }); diff --git a/lib/Controller/FileCSVController.php b/lib/Controller/FileCSVController.php index 2dce3ea4e..110269b99 100644 --- a/lib/Controller/FileCSVController.php +++ b/lib/Controller/FileCSVController.php @@ -28,10 +28,12 @@ use OCA\Workspace\Files\Csv; use OCA\Workspace\Files\InternalFile; use OCA\Workspace\Files\LocalFile; +use OCA\Workspace\Middleware\Attribute\SpaceAdminRequired; use OCA\Workspace\Service\UserService; use OCA\Workspace\Service\WorkspaceService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\Files\IRootFolder; use OCP\Files\Node; @@ -57,11 +59,10 @@ public function __construct( } /** - * @NoAdminRequired - * @SpaceAdminRequired * Returns formatted list of existing users of the instance. - * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function import(): JSONResponse { $params = $this->request->getParams(); $spaceObj = $params['space']; @@ -116,11 +117,10 @@ public function import(): JSONResponse { } /** - * @NoAdminRequired - * @SpaceAdminRequired * Returns formatted list of existing users of the instance. - * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function getFromFiles():JSONResponse { $params = $this->request->getParams(); $path = $params['path']; diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index f9493e8fe..ff48a703e 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -25,6 +25,8 @@ namespace OCA\Workspace\Controller; +use OCA\Workspace\Middleware\Attribute\GeneralManagerRequired; +use OCA\Workspace\Middleware\Attribute\SpaceAdminRequired; use OCA\Workspace\Service\Group\GroupFolder\GroupFolderManage; use OCA\Workspace\Service\Group\GroupFormatter; use OCA\Workspace\Service\Group\GroupsWorkspaceService; @@ -36,6 +38,7 @@ use OCA\Workspace\Service\UserService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IGroupManager; use OCP\IRequest; @@ -60,9 +63,6 @@ public function __construct( } /** - * @NoAdminRequired - * @SpaceAdminRequired - * * Creates a group * NB: This function could probably be abused by space managers to create arbitrary group. But, do we really care? * @@ -73,6 +73,8 @@ public function __construct( * @var string $spaceId for Middleware * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function create(array $data = []): JSONResponse { $data = array_merge(self::DEFAULT, $data); @@ -100,9 +102,6 @@ public function create(array $data = []): JSONResponse { } /** - * @NoAdminRequired - * @SpaceAdminRequired - * * Deletes a group * Cannot delete GE- and U- groups (This is on-purpose) * @@ -110,6 +109,8 @@ public function create(array $data = []): JSONResponse { * @var int $spaceId * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function delete(string $gid, int $spaceId): JSONResponse { // TODO Use groupfolder api to retrieve workspace group. if (substr($gid, -strlen($spaceId)) != $spaceId) { @@ -132,9 +133,6 @@ public function delete(string $gid, int $spaceId): JSONResponse { } /** - * @NoAdminRequired - * @SpaceAdminRequired - * * Renames a group * Cannot rename GE- and U- groups (This is on-purpose) * @@ -143,6 +141,8 @@ public function delete(string $gid, int $spaceId): JSONResponse { * @var int $spaceId * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function rename(string $newGroupName, string $gid, int $spaceId): JSONResponse { @@ -176,8 +176,6 @@ public function rename(string $newGroupName, } /** - * @NoAdminRequired - * @SpaceAdminRequired * Adds a user to a group. * The function automaticaly adds the user the the corresponding workspace's user group, and to the application * manager group when we are adding a workspace manager @@ -187,6 +185,8 @@ public function rename(string $newGroupName, * @var string $user * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function addUser(string $spaceId, string $gid, string $user): JSONResponse { // Makes sure group exist $NCGroup = $this->groupManager->get($gid); @@ -226,14 +226,13 @@ public function addUser(string $spaceId, string $gid, string $user): JSONRespons /** * Remove a user from a workspace. * - * @NoAdminRequired - * @SpaceAdminRequired - * * @param array|string $space * @param string $gid * @param string $user * @return JSONResponse */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function removeUserFromWorkspace( array|string $space, string $gid, @@ -283,9 +282,6 @@ public function removeUserFromWorkspace( } /** - * @NoAdminRequired - * @SpaceAdminRequired - * * Removes a user from a group * The function also remove the user from all workspace 'subgroup when the user is being removed from the U- group * and from the WorkspacesManagers group when the user is being removed from the GE- group @@ -295,6 +291,8 @@ public function removeUserFromWorkspace( * @var string $user * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function removeUser( IRequest $request, array|string $space, @@ -370,11 +368,11 @@ public function removeUser( } /** - * @NoAdminRequired - * @GeneralManagerRequired + * @param string $spaceId * @param string|array $groupfolder - * */ + #[NoAdminRequired] + #[GeneralManagerRequired] public function transferUsersToGroups(string $spaceId, string|array $groupfolder): JSONResponse { if (gettype($groupfolder) === 'string') { diff --git a/lib/Controller/PageController.php b/lib/Controller/PageController.php index df78af9da..c7e6711b3 100644 --- a/lib/Controller/PageController.php +++ b/lib/Controller/PageController.php @@ -28,6 +28,8 @@ use OCA\Workspace\AppInfo\Application; use OCA\Workspace\Service\UserService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\TemplateResponse; use OCP\Util; @@ -40,9 +42,9 @@ public function __construct( /** * Application's main page * - * @NoAdminRequired - * @NOCSRFRequired */ + #[NoAdminRequired] + #[NoCSRFRequired] public function index(): TemplateResponse { Util::addScript(Application::APP_ID, 'workspace-main'); // js/workspace-main.js Util::addStyle(Application::APP_ID, 'workspace-style'); // css/workspace-style.css diff --git a/lib/Controller/SpaceController.php b/lib/Controller/SpaceController.php index be73c7364..95f739492 100644 --- a/lib/Controller/SpaceController.php +++ b/lib/Controller/SpaceController.php @@ -26,8 +26,10 @@ namespace OCA\Workspace\Controller; use OCA\Workspace\Db\SpaceMapper; +use OCA\Workspace\Middleware\Attribute\SpaceAdminRequired; use OCA\Workspace\Service\SpaceService; use OCP\AppFramework\Controller; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; use OCP\IRequest; @@ -42,23 +44,24 @@ public function __construct( } /** - * @NoAdminRequired + * @param $id - The space id to get a space - OCA\Workspace\Db\Space . + * @return DataResponse - The space serialized */ + #[NoAdminRequired] public function find(int $id): DataResponse { return new DataResponse($this->spaceService->find($id)); } - /** - * @NoAdminRequired - */ + #[NoAdminRequired] public function findAll(): DataResponse { return new DataResponse($this->spaceService->findAll()); } /** - * @NoAdminRequired - * @SpaceAdminRequired + * @return DataResponse - The space serialized */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function updateColorCode(string $colorCode, int $spaceId): DataResponse { return new DataResponse($this->spaceService->updateColorCode($colorCode, (int)$spaceId)); } diff --git a/lib/Controller/WorkspaceController.php b/lib/Controller/WorkspaceController.php index e9a0f2d3b..3c3e270a1 100644 --- a/lib/Controller/WorkspaceController.php +++ b/lib/Controller/WorkspaceController.php @@ -33,6 +33,8 @@ use OCA\Workspace\Exceptions\WorkspaceNameExistException; use OCA\Workspace\Folder\RootFolder; use OCA\Workspace\Helper\GroupfolderHelper; +use OCA\Workspace\Middleware\Attribute\GeneralManagerRequired; +use OCA\Workspace\Middleware\Attribute\SpaceAdminRequired; use OCA\Workspace\Service\Group\GroupFormatter; use OCA\Workspace\Service\Group\ManagersWorkspace; use OCA\Workspace\Service\Group\UserGroup; @@ -43,6 +45,7 @@ use OCA\Workspace\Service\WorkspaceService; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\JSONResponse; use OCP\IGroupManager; use OCP\IRequest; @@ -79,14 +82,14 @@ private function deleteBlankSpaceName(string $spaceName): string { } /** - * @NoAdminRequired - * @GeneralManagerRequired * @param string $spaceName * @param int $folderId * @throws BadRequestException * @throws CreateWorkspaceException * @throws CreateGroupException */ + #[NoAdminRequired] + #[GeneralManagerRequired] public function createWorkspace(string $spaceName, int $folderId): JSONResponse { if ($spaceName === false || @@ -138,11 +141,11 @@ public function createWorkspace(string $spaceName, * * Deletes the workspace, and the corresponding groupfolder and groups * - * @NoAdminRequired - * @GeneralManagerRequired * @param array $workspace * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function destroy(array $workspace): JSONResponse { $this->logger->debug('Removing GE users from the WorkspacesManagers group if needed.'); $GEGroup = $this->groupManager->get(WorkspaceManagerGroup::get($workspace['id'])); @@ -179,9 +182,8 @@ public function destroy(array $workspace): JSONResponse { * * Returns a list of all the workspaces that the connected user may use. * - * @NoAdminRequired - * */ + #[NoAdminRequired] public function findAll(): JSONResponse { $workspaces = $this->workspaceService->getAll(); $spaces = []; @@ -215,17 +217,17 @@ public function findAll(): JSONResponse { } /** - * @NoAdminRequired * @param string|array $workspace */ + #[NoAdminRequired] public function addGroupsInfo(string|array $workspace): JSONResponse { return new JSONResponse($this->workspaceService->addGroupsInfo($workspace)); } /** - * @NoAdminRequired * @param string|array $workspace */ + #[NoAdminRequired] public function addUsersInfo(string|array $workspace): JSONResponse { if (gettype($workspace) === 'string') { $workspace = json_decode($workspace, true); @@ -236,12 +238,12 @@ public function addUsersInfo(string|array $workspace): JSONResponse { /** * Returns a list of users whose name matches $term * - * @NoAdminRequired * @param string $term * @param string $spaceId * @param string|array $space * */ + #[NoAdminRequired] public function lookupUsers(string $term, string $spaceId, string|array $space): JSONResponse { @@ -256,13 +258,13 @@ public function lookupUsers(string $term, * * Change a user's role in a workspace * - * @NoAdminRequired - * @SpaceAdminRequired * * @param array|string $space * @param string $userId * */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function changeUserRole(array|string $space, string $userId): JSONResponse { if (gettype($space) === 'string') { @@ -289,13 +291,13 @@ public function changeUserRole(array|string $space, /** * - * @NoAdminRequired - * @SpaceAdminRequired * @param array|string $workspace * @param string $newSpaceName * * @todo Manage errors */ + #[NoAdminRequired] + #[SpaceAdminRequired] public function renameSpace(array|string $workspace, string $newSpaceName): JSONResponse { if (gettype($workspace) === 'string') { diff --git a/lib/Middleware/Attribute/GeneralManagerRequired.php b/lib/Middleware/Attribute/GeneralManagerRequired.php new file mode 100644 index 000000000..53f8af0a2 --- /dev/null +++ b/lib/Middleware/Attribute/GeneralManagerRequired.php @@ -0,0 +1,29 @@ + + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Middleware\Attribute; + +use Attribute; + +#[Attribute(Attribute::TARGET_METHOD)] +class GeneralManagerRequired { +} diff --git a/lib/Middleware/Attribute/SapceAdminRequired.php b/lib/Middleware/Attribute/SapceAdminRequired.php new file mode 100644 index 000000000..22674d409 --- /dev/null +++ b/lib/Middleware/Attribute/SapceAdminRequired.php @@ -0,0 +1,29 @@ + + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + +namespace OCA\Workspace\Middleware\Attribute; + +use Attribute; + +#[Attribute(Attribute::TARGET_METHOD)] +class SpaceAdminRequired { +} diff --git a/lib/Middleware/IsGeneralManagerMiddleware.php b/lib/Middleware/IsGeneralManagerMiddleware.php index 346899770..22e18b4d6 100644 --- a/lib/Middleware/IsGeneralManagerMiddleware.php +++ b/lib/Middleware/IsGeneralManagerMiddleware.php @@ -26,24 +26,24 @@ namespace OCA\Workspace\Middleware; use Exception; +use OCA\Workspace\Middleware\Attribute\GeneralManagerRequired; use OCA\Workspace\Middleware\Exceptions\AccessDeniedException; use OCA\Workspace\Service\UserService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Middleware; -use OCP\AppFramework\Utility\IControllerMethodReflector; -use OCP\IRequest; class IsGeneralManagerMiddleware extends Middleware { + public function __construct( - private IControllerMethodReflector $reflector, - private IRequest $request, private UserService $userService ) { } public function beforeController($controller, $methodName): void { - if ($this->reflector->hasAnnotation('GeneralManagerRequired')) { + $reflectionMethod = new \ReflectionMethod($controller, $methodName); + $hasAttribute = !empty($reflectionMethod->getAttributes(GeneralManagerRequired::class)); + if ($hasAttribute) { if (!$this->userService->isUserGeneralAdmin()) { throw new AccessDeniedException(); } @@ -59,5 +59,14 @@ public function afterException($controller, $methodName, Exception $exception): 'msg' => 'You are not allowed to perform this action' ], Http::STATUS_FORBIDDEN); } + + return new JSONResponse([ + 'message' => 'Impossible to catch the exception from the ' . $this::class, + 'exception' => [ + 'class' => $exception::class, + 'message' => $exception->getMessage(), + 'trace' => $exception->getTrace() + ] + ]); } } diff --git a/lib/Middleware/IsSpaceAdminMiddleware.php b/lib/Middleware/IsSpaceAdminMiddleware.php index 269a04068..0d78e39c1 100644 --- a/lib/Middleware/IsSpaceAdminMiddleware.php +++ b/lib/Middleware/IsSpaceAdminMiddleware.php @@ -25,18 +25,18 @@ namespace OCA\Workspace\Middleware; +use OCA\Workspace\Middleware\Attribute\SpaceAdminRequired; use OCA\Workspace\Middleware\Exceptions\AccessDeniedException; use OCA\Workspace\Service\SpaceService; use OCA\Workspace\Service\UserService; use OCP\AppFramework\Http; use OCP\AppFramework\Http\JSONResponse; use OCP\AppFramework\Middleware; -use OCP\AppFramework\Utility\IControllerMethodReflector; use OCP\IRequest; class IsSpaceAdminMiddleware extends Middleware { + public function __construct( - private IControllerMethodReflector $reflector, private IRequest $request, private UserService $userService, private SpaceService $spaceService @@ -44,7 +44,9 @@ public function __construct( } public function beforeController($controller, $methodName): void { - if ($this->reflector->hasAnnotation('SpaceAdminRequired')) { + $reflectionMethod = new \ReflectionMethod($controller, $methodName); + $hasAttribute = !empty($reflectionMethod->getAttributes(SpaceAdminRequired::class)); + if ($hasAttribute) { $spaceId = $this->request->getParam('spaceId'); $space = $this->spaceService->find($spaceId); if (!$this->userService->isSpaceManagerOfSpace($space->jsonSerialize()) && !$this->userService->isUserGeneralAdmin()) { @@ -61,6 +63,13 @@ public function afterException($controller, $methodName, \Exception $exception): ], Http::STATUS_FORBIDDEN); } - return new JSONResponse([]); + return new JSONResponse([ + 'message' => 'Impossible to catch the exception from the ' . $this::class, + 'exception' => [ + 'class' => $exception::class, + 'message' => $exception->getMessage(), + 'trace' => $exception->getTrace() + ] + ]); } }