From d604ca685ac5705d1ae22faccc5213ce0db54311 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 14:43:47 +0200 Subject: [PATCH 01/11] Improves README. --- README.md | 70 ++++++++----------------------------------------------- 1 file changed, 10 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index a9e73d3..64ebc9a 100644 --- a/README.md +++ b/README.md @@ -1,72 +1,22 @@ -# S C I M Server -Place this app in **nextcloud/apps/** - -## Building the app - -The app can be built by using the provided Makefile by running: - - make - -This requires the following things to be present: -* make -* which -* tar: for building the archive -* curl: used if phpunit and composer are not installed to fetch them from the web -* npm: for building and testing everything JS, only required if a package.json is placed inside the **js/** folder - -The make command will install or update Composer dependencies if a composer.json is present and also **npm run build** if a package.json is present in the **js/** folder. The npm **build** script should use local paths for build systems and package managers, so people that simply want to build the app won't need to install npm libraries globally, e.g.: - -**package.json**: -```json -"scripts": { - "test": "node node_modules/gulp-cli/bin/gulp.js karma", - "prebuild": "npm install && node_modules/bower/bin/bower install && node_modules/bower/bin/bower update", - "build": "node node_modules/gulp-cli/bin/gulp.js" -} -``` - - -## Publish to App Store - -First get an account for the [App Store](http://apps.nextcloud.com/) then run: - - make && make appstore - -The archive is located in build/artifacts/appstore and can then be uploaded to the App Store. +# SCIM Service Provider ## Running tests -You can use the provided Makefile to run all tests by using: - make test +To run the test, you can use [insomnia UI](https://docs.insomnia.rest). -This will run the PHP unit and integration tests and if a package.json is present in the **js/** folder will execute **npm run test** +![screenshot insomnia ui](./screenshots/insomnia.png) -Of course you can also install [PHPUnit](http://phpunit.de/getting-started.html) and use the configurations directly: +For CI, there is still [a bug](https://github.com/Kong/insomnia/issues/4747) we need to find a fix. - phpunit -c phpunit.xml +## TODO -or: +## Quick "Deploy" to test - phpunit -c phpunit.integration.xml - -for integration tests - -# TODO - - - [x]attribute active - - group mgmt - - list user - - add/remove user from groups - - update, displayName - - Erreur/Exception - - [x] json - - [x] status code - - [x] escaped location - JSON_UNESCAPED_SLASHES - - - cd apps +``` +cd apps wget https://lab.libreho.st/libre.sh/scim/nextcloud-scim/-/archive/test-branch/nextcloud-scim-main.zip unzip nextcloud-scim-main.zip rm nextcloud-scim-main.zip rm -rf scimserviceprovider -mv nextcloud-scim-test-branchxxx scimserviceprovider \ No newline at end of file +mv nextcloud-scim-main scimserviceprovider +``` \ No newline at end of file From ad99a0ee826687b9213b474445b7e17c09f45d29 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 14:44:21 +0200 Subject: [PATCH 02/11] Removes unecessary code. --- lib/Controller/UserController.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 69498a4..f760837 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -120,10 +120,6 @@ class UserController extends ASCIMUser { // Do not insert empty entry if (!empty($SCIMUser)) { $SCIMUsers[] = $SCIMUser; - } else { - // Logged user does not have permissions to see this user - // only showing its id - $SCIMUsers[$userId] = ['id' => $userId]; } } From b426c7ad1a0a488fff6f75904a93b649cc9c4457 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 14:44:29 +0200 Subject: [PATCH 03/11] Fixes readme. --- screenshots/insomnia.png | Bin 0 -> 127822 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 screenshots/insomnia.png diff --git a/screenshots/insomnia.png b/screenshots/insomnia.png new file mode 100644 index 0000000000000000000000000000000000000000..3cbd8745fdbde489e8c6177096c79a13b9068e04 GIT binary patch literal 127822 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 literal 0 HcmV?d00001 From dfa2d89ad53ab5823b8b0a65d6c32b0f5326b09c Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 14:44:40 +0200 Subject: [PATCH 04/11] Adds groups. --- appinfo/routes.php | 3 +- lib/Controller/ASCIMGroup.php | 119 +++++++++++ lib/Controller/GroupController.php | 225 +++++++++++++++++++ lib/Controller/GroupsController.php | 320 ---------------------------- 4 files changed, 346 insertions(+), 321 deletions(-) create mode 100644 lib/Controller/ASCIMGroup.php create mode 100644 lib/Controller/GroupController.php delete mode 100644 lib/Controller/GroupsController.php diff --git a/appinfo/routes.php b/appinfo/routes.php index 0e3f288..f023c1b 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -27,6 +27,7 @@ */ return [ 'resources' => [ - 'user' => ['url' => '/Users'] + 'user' => ['url' => '/Users'], + 'group' => ['url' => '/Groups'] ] ]; diff --git a/lib/Controller/ASCIMGroup.php b/lib/Controller/ASCIMGroup.php new file mode 100644 index 0000000..1ef999c --- /dev/null +++ b/lib/Controller/ASCIMGroup.php @@ -0,0 +1,119 @@ + + * + * @author Arthur Schiwon + * @author Christoph Wurst + * @author Georg Ehrke + * @author Joas Schilling + * @author John Molakvoæ + * @author Roeland Jago Douma + * @author Vincent Petry + * + * @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\SCIMServiceProvider\Controller; + +use OC\Group\Manager; +use OCP\Accounts\IAccountManager; +use OCP\Accounts\PropertyDoesNotExistException; +use OCP\AppFramework\ApiController; +use OCP\AppFramework\Http; +use OCP\Files\NotFoundException; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IRequest; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\L10N\IFactory; +use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; +use OCP\AppFramework\Http\DataResponse; +use OCP\IUser; +use Psr\Log\LoggerInterface; + +abstract class ASCIMGroup extends ApiController { + /** @var IUserManager */ + protected $userManager; + /** @var IConfig */ + protected $config; + /** @var IGroupManager|Manager */ // FIXME Requires a method that is not on the interface + protected $groupManager; + /** @var IUserSession */ + protected $userSession; + /** @var IAccountManager */ + protected $accountManager; + + public function __construct(string $appName, + IRequest $request, + IUserManager $userManager, + IConfig $config, + IGroupManager $groupManager, + IUserSession $userSession, + IAccountManager $accountManager) { + parent::__construct($appName, $request); + + $this->userManager = $userManager; + $this->config = $config; + $this->groupManager = $groupManager; + $this->userSession = $userSession; + $this->accountManager = $accountManager; + } + + /** + * creates an object with all group data + * + * @param string $groupId + * @param bool $includeScopes + * @return array + * @throws Exception + */ + protected function getSCIMGroup(string $groupId): array { + $groupId = urldecode($groupId); + + // Check the group exists + $group = $this->groupManager->get($groupId); + if ($group === null) { + return []; + } + + $members = array(); + foreach ($this->groupManager->get($groupId)->getUsers() as $member) { + $members[] = [ + 'value' => $member->getUID(), + '$ref' => '/Users/' . $member->getUID(), + 'display' => $member->getDisplayName() + ]; + } + + return [ + 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group'], + 'id' => $groupId, + 'displayName' => $group->getDisplayName(), + 'externalId' => '1234', // todo + 'meta' => [ + 'resourceType' => 'Group', + 'location' => '/Groups/' . $groupId, + 'created' => '2022-04-28T18:27:17.783Z', // todo + 'lastModified' => '2022-04-28T18:27:17.783Z' // todo + ], + 'members' => $members + ]; + } +} diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php new file mode 100644 index 0000000..1dd44a2 --- /dev/null +++ b/lib/Controller/GroupController.php @@ -0,0 +1,225 @@ + + * @author Bjoern Schiessle + * @author Christoph Wurst + * @author Daniel Calviño Sánchez + * @author Daniel Kesselberg + * @author Joas Schilling + * @author John Molakvoæ + * @author Julius Härtl + * @author Lukas Reschke + * @author michag86 + * @author Mikael Hammarin + * @author Morris Jobke + * @author Robin Appelman + * @author Roeland Jago Douma + * @author Sujith Haridasan + * @author Thomas Citharel + * @author Thomas Müller + * @author Tom Needham + * @author Vincent Petry + * + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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, version 3, + * along with this program. If not, see + * + */ +namespace OCA\SCIMServiceProvider\Controller; + +use InvalidArgumentException; +use OC\HintException; +use OC\KnownUser\KnownUserService; +use OCP\Accounts\IAccountManager; +use OCP\AppFramework\OCS\OCSException; +use OCP\AppFramework\OCSController; +use OCP\AppFramework\Http\Response; +use OCP\IConfig; +use OCP\IGroupManager; +use OCP\IRequest; +use OCP\IURLGenerator; +use OCP\IUserManager; +use OCP\IUserSession; +use OCP\Security\ISecureRandom; +use OCP\EventDispatcher\IEventDispatcher; +use Psr\Log\LoggerInterface; +use OCA\SCIMServiceProvider\Responses\SCIMListResponse; +use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; +use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; + + +class GroupController extends ASCIMGroup { + + /** @var IURLGenerator */ + protected $urlGenerator; + /** @var LoggerInterface */ + private $logger; + /** @var ISecureRandom */ + private $secureRandom; + /** @var KnownUserService */ + private $knownUserService; + /** @var IEventDispatcher */ + private $eventDispatcher; + + public function __construct(string $appName, + IRequest $request, + IUserManager $userManager, + IConfig $config, + IGroupManager $groupManager, + IUserSession $userSession, + IAccountManager $accountManager, + IURLGenerator $urlGenerator, + LoggerInterface $logger, + ISecureRandom $secureRandom, + KnownUserService $knownUserService, + IEventDispatcher $eventDispatcher) { + parent::__construct($appName, + $request, + $userManager, + $config, + $groupManager, + $userSession, + $accountManager); + + $this->urlGenerator = $urlGenerator; + $this->logger = $logger; + $this->secureRandom = $secureRandom; + $this->knownUserService = $knownUserService; + $this->eventDispatcher = $eventDispatcher; + } + + /** + * @NoCSRFRequired + * + * returns a list of groups and their data + */ + public function index(): SCIMListResponse { + $SCIMGroups = $this->groupManager->search('', null, 0); + $SCIMGroups = array_map(function ($group) { + return $this->getSCIMGroup($group->getGID()); + }, $SCIMGroups); + return new SCIMListResponse($SCIMGroups); + } + + /** + * @NoCSRFRequired + * + * gets group info + * + * @param string $id + * @return SCIMJSONResponse + * @throws Exception + */ + public function show(string $id): SCIMJSONResponse { + $group = $this->getSCIMGroup($id); + // getUserData returns empty array if not enough permissions + if (empty($group)) { + return new SCIMErrorResponse(['message' => 'Group not found'], 404); + } + return new SCIMJSONResponse($group); + } + + /** + * @NoCSRFRequired + * + * @param string $displayName + * @param array $members + * @return SCIMJSONResponse + * @throws Exception + */ + public function create( string $displayName = '', + array $members = []): SCIMJSONResponse { + + $id=urldecode($displayName); + // Validate name + if (empty($id)) { + $this->logger->error('Group name not supplied', ['app' => 'provisioning_api']); + return new SCIMErrorResponse(['message' => 'Invalid group name'], 101); + } + // Check if it exists + if ($this->groupManager->groupExists($id)) { + return new SCIMErrorResponse(['message' => 'Group exists'], 409); + } + $group = $this->groupManager->createGroup($id); + if ($group === null) { + return new SCIMErrorResponse(['message' => 'Not supported by backend'], 103); + } + if ($displayname !== '') { + $group->setDisplayName($displayName); + } + foreach ($members as $member) { + $targetUser = $this->userManager->get($member['value']); + $group->addUser($targetUser); + } + return new SCIMJSONResponse($this->getSCIMGroup($id)); + } + + + /** + * @NoCSRFRequired + * + * @param string $id + * + * @param bool $active + * @param string $displayName + * @param array $emails + * @return DataResponse + * @throws Exception + */ + public function update( string $id, + bool $active, + string $displayName = '', + array $emails = []): SCIMJSONResponse { + $targetUser = $this->userManager->get($id); + if ($targetUser === null) { + return new SCIMErrorResponse(['message' => 'User not found'], 404); + } + foreach ($emails as $email) { + if ($email['primary'] === true) { + $targetUser->setEMailAddress($email['value']); + } + } + if (isset($active)) { + $targetUser->setEnabled($active); + } + return new SCIMJSONResponse($this->getSCIMUser($id)); + + } + + /** + * @NoCSRFRequired + * + * @param string $id + * @return DataResponse + */ + public function destroy(string $id): Response { + $groupId = urldecode($id); + + // Check it exists + if (!$this->groupManager->groupExists($groupId)) { + return new SCIMErrorResponse(['message' => 'Group not found'], 404); + } elseif ($groupId === 'admin' || !$this->groupManager->get($groupId)->delete()) { + // Cannot delete admin group + return new SCIMErrorResponse(['message' => 'Can\'t delete this group, not enough rights or admin group'], 403); + } + $response = new Response(); + $response->setStatus(204); + return $response; + } + +} diff --git a/lib/Controller/GroupsController.php b/lib/Controller/GroupsController.php deleted file mode 100644 index 8336449..0000000 --- a/lib/Controller/GroupsController.php +++ /dev/null @@ -1,320 +0,0 @@ - - * @author Christoph Wurst - * @author Joas Schilling - * @author John Molakvoæ - * @author Julius Härtl - * @author Lukas Reschke - * @author Robin Appelman - * @author Roeland Jago Douma - * @author Tom Needham - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ -namespace OCA\SCIMServiceProvider\Controller; - -use OCP\Accounts\IAccountManager; -use OCP\AppFramework\Http\DataResponse; -use OCP\AppFramework\OCSController; -use OCP\IConfig; -use OCP\IGroup; -use OCP\IGroupManager; -use OCP\IRequest; -use OCP\IUser; -use OCP\IUserManager; -use OCP\IUserSession; -use Psr\Log\LoggerInterface; - -class GroupsController extends AUserData { - - /** @var LoggerInterface */ - private $logger; - - public function __construct(string $appName, - IRequest $request, - IUserManager $userManager, - IConfig $config, - IGroupManager $groupManager, - IUserSession $userSession, - IAccountManager $accountManager, - LoggerInterface $logger) { - parent::__construct($appName, - $request, - $userManager, - $config, - $groupManager, - $userSession, - $accountManager - ); - - $this->logger = $logger; - } - - /** - * returns a list of groups - * - * @NoAdminRequired - * - * @param string $search - * @param int $limit - * @param int $offset - * @return DataResponse - */ - public function getGroups(string $search = '', int $limit = null, int $offset = 0): DataResponse { - $groups = $this->groupManager->search($search, $limit, $offset); - $groups = array_map(function ($group) { - /** @var IGroup $group */ - return $group->getGID(); - }, $groups); - - return new DataResponse(['groups' => $groups]); - } - - /** - * returns a list of groups details with ids and displaynames - * - * @NoAdminRequired - * - * @param string $search - * @param int $limit - * @param int $offset - * @return DataResponse - */ - public function getGroupsDetails(string $search = '', int $limit = null, int $offset = 0): DataResponse { - $groups = $this->groupManager->search($search, $limit, $offset); - $groups = array_map(function ($group) { - /** @var IGroup $group */ - return [ - 'id' => $group->getGID(), - 'displayname' => $group->getDisplayName(), - 'usercount' => $group->count(), - 'disabled' => $group->countDisabled(), - 'canAdd' => $group->canAddUser(), - 'canRemove' => $group->canRemoveUser(), - ]; - }, $groups); - - return new DataResponse(['groups' => $groups]); - } - - /** - * @NoAdminRequired - * - * @param string $groupId - * @return DataResponse - * @throws OCSException - * - * @deprecated 14 Use getGroupUsers - */ - public function getGroup(string $groupId): DataResponse { - return $this->getGroupUsers($groupId); - } - - /** - * returns an array of users in the specified group - * - * @NoAdminRequired - * - * @param string $groupId - * @return DataResponse - * @throws OCSException - */ - public function getGroupUsers(string $groupId): DataResponse { - $groupId = urldecode($groupId); - - $user = $this->userSession->getUser(); - $isSubadminOfGroup = false; - - // Check the group exists - $group = $this->groupManager->get($groupId); - if ($group !== null) { - $isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($user, $group); - } else { - throw new OCSNotFoundException('The requested group could not be found'); - } - - // Check subadmin has access to this group - if ($this->groupManager->isAdmin($user->getUID()) - || $isSubadminOfGroup) { - $users = $this->groupManager->get($groupId)->getUsers(); - $users = array_map(function ($user) { - /** @var IUser $user */ - return $user->getUID(); - }, $users); - $users = array_values($users); - return new DataResponse(['users' => $users]); - } - - throw new OCSForbiddenException(); - } - - /** - * returns an array of users details in the specified group - * - * @NoAdminRequired - * - * @param string $groupId - * @param string $search - * @param int $limit - * @param int $offset - * @return DataResponse - * @throws OCSException - */ - public function getGroupUsersDetails(string $groupId, string $search = '', int $limit = null, int $offset = 0): DataResponse { - $groupId = urldecode($groupId); - $currentUser = $this->userSession->getUser(); - - // Check the group exists - $group = $this->groupManager->get($groupId); - if ($group !== null) { - $isSubadminOfGroup = $this->groupManager->getSubAdmin()->isSubAdminOfGroup($currentUser, $group); - } else { - throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND); - } - - // Check subadmin has access to this group - if ($this->groupManager->isAdmin($currentUser->getUID()) || $isSubadminOfGroup) { - $users = $group->searchUsers($search, $limit, $offset); - - // Extract required number - $usersDetails = []; - foreach ($users as $user) { - try { - /** @var IUser $user */ - $userId = (string)$user->getUID(); - $userData = $this->getUserData($userId); - // Do not insert empty entry - if (!empty($userData)) { - $usersDetails[$userId] = $userData; - } else { - // Logged user does not have permissions to see this user - // only showing its id - $usersDetails[$userId] = ['id' => $userId]; - } - } catch (OCSNotFoundException $e) { - // continue if a users ceased to exist. - } - } - return new DataResponse(['users' => $usersDetails]); - } - - throw new OCSException('The requested group could not be found', OCSController::RESPOND_NOT_FOUND); - } - - /** - * creates a new group - * - * @PasswordConfirmationRequired - * - * @param string $groupid - * @param string $displayname - * @return DataResponse - * @throws OCSException - */ - public function addGroup(string $groupid, string $displayname = ''): DataResponse { - // Validate name - if (empty($groupid)) { - $this->logger->error('Group name not supplied', ['app' => 'provisioning_api']); - throw new OCSException('Invalid group name', 101); - } - // Check if it exists - if ($this->groupManager->groupExists($groupid)) { - throw new OCSException('group exists', 102); - } - $group = $this->groupManager->createGroup($groupid); - if ($group === null) { - throw new OCSException('Not supported by backend', 103); - } - if ($displayname !== '') { - $group->setDisplayName($displayname); - } - return new DataResponse(); - } - - /** - * @PasswordConfirmationRequired - * - * @param string $groupId - * @param string $key - * @param string $value - * @return DataResponse - * @throws OCSException - */ - public function updateGroup(string $groupId, string $key, string $value): DataResponse { - $groupId = urldecode($groupId); - - if ($key === 'displayname') { - $group = $this->groupManager->get($groupId); - if ($group->setDisplayName($value)) { - return new DataResponse(); - } - - throw new OCSException('Not supported by backend', 101); - } else { - throw new OCSException('', OCSController::RESPOND_UNKNOWN_ERROR); - } - } - - /** - * @PasswordConfirmationRequired - * - * @param string $groupId - * @return DataResponse - * @throws OCSException - */ - public function deleteGroup(string $groupId): DataResponse { - $groupId = urldecode($groupId); - - // Check it exists - if (!$this->groupManager->groupExists($groupId)) { - throw new OCSException('', 101); - } elseif ($groupId === 'admin' || !$this->groupManager->get($groupId)->delete()) { - // Cannot delete admin group - throw new OCSException('', 102); - } - - return new DataResponse(); - } - - /** - * @param string $groupId - * @return DataResponse - * @throws OCSException - */ - public function getSubAdminsOfGroup(string $groupId): DataResponse { - // Check group exists - $targetGroup = $this->groupManager->get($groupId); - if ($targetGroup === null) { - throw new OCSException('Group does not exist', 101); - } - - /** @var IUser[] $subadmins */ - $subadmins = $this->groupManager->getSubAdmin()->getGroupsSubAdmins($targetGroup); - // New class returns IUser[] so convert back - $uids = []; - foreach ($subadmins as $user) { - $uids[] = $user->getUID(); - } - - return new DataResponse($uids); - } -} From 3d786f8df65f35d636bec6d3e604ced032a0886d Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 14:51:53 +0200 Subject: [PATCH 05/11] Implements group update. --- lib/Controller/GroupController.php | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index 1dd44a2..044e3fe 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -175,30 +175,21 @@ class GroupController extends ASCIMGroup { * * @param string $id * - * @param bool $active * @param string $displayName - * @param array $emails + * @param array $members * @return DataResponse * @throws Exception */ public function update( string $id, - bool $active, string $displayName = '', - array $emails = []): SCIMJSONResponse { - $targetUser = $this->userManager->get($id); - if ($targetUser === null) { - return new SCIMErrorResponse(['message' => 'User not found'], 404); + array $members = []): SCIMJSONResponse { + $group = $this->groupManager->get($id); + foreach ($members as $member) { + $targetUser = $this->userManager->get($member['value']); + $group->addUser($targetUser); + // todo implement member removal (: } - foreach ($emails as $email) { - if ($email['primary'] === true) { - $targetUser->setEMailAddress($email['value']); - } - } - if (isset($active)) { - $targetUser->setEnabled($active); - } - return new SCIMJSONResponse($this->getSCIMUser($id)); - + return new SCIMJSONResponse($this->getSCIMGroup($id)); } /** From 15c29d3305c051487f99a77efcaab026156deaa4 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 15:23:47 +0200 Subject: [PATCH 06/11] Fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 64ebc9a..0e188da 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ For CI, there is still [a bug](https://github.com/Kong/insomnia/issues/4747) we ``` cd apps -wget https://lab.libreho.st/libre.sh/scim/nextcloud-scim/-/archive/test-branch/nextcloud-scim-main.zip +wget https://lab.libreho.st/libre.sh/scim/nextcloud-scim/-/archive/main/nextcloud-scim-main.zip unzip nextcloud-scim-main.zip rm nextcloud-scim-main.zip rm -rf scimserviceprovider From cc6f90b1077089fe13713c7c546d4f384760c475 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 15:24:27 +0200 Subject: [PATCH 07/11] Fixes wrong error code. --- lib/Controller/GroupController.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index 044e3fe..fcad879 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -145,11 +145,11 @@ class GroupController extends ASCIMGroup { public function create( string $displayName = '', array $members = []): SCIMJSONResponse { - $id=urldecode($displayName); + $id = urlencode($displayName); // Validate name if (empty($id)) { $this->logger->error('Group name not supplied', ['app' => 'provisioning_api']); - return new SCIMErrorResponse(['message' => 'Invalid group name'], 101); + return new SCIMErrorResponse(['message' => 'Invalid group name'], 400); } // Check if it exists if ($this->groupManager->groupExists($id)) { @@ -159,10 +159,9 @@ class GroupController extends ASCIMGroup { if ($group === null) { return new SCIMErrorResponse(['message' => 'Not supported by backend'], 103); } - if ($displayname !== '') { - $group->setDisplayName($displayName); - } + $group->setDisplayName($displayName); foreach ($members as $member) { + $this->logger->error('Group name not supplied' . $member['value'], ['app' => 'provisioning_api']); $targetUser = $this->userManager->get($member['value']); $group->addUser($targetUser); } @@ -184,6 +183,9 @@ class GroupController extends ASCIMGroup { string $displayName = '', array $members = []): SCIMJSONResponse { $group = $this->groupManager->get($id); + if (!$this->groupManager->groupExists($id)) { + return new SCIMErrorResponse(['message' => 'Group not found'], 404); + } foreach ($members as $member) { $targetUser = $this->userManager->get($member['value']); $group->addUser($targetUser); From e84ec1550175b1574ce965007b4373da448db9a9 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 15:52:56 +0200 Subject: [PATCH 08/11] Improves README. --- README.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0e188da..2bc1d04 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ # SCIM Service Provider +This app allows to provision users and groups in Nextcloud from a scim client. + +You can see the video that shows how it works. + +![video presentation](https://hot-objects.liiib.re/meet-liiib-re-recordings/pair_2022-05-02-15-40-37.mp4) + +## How to use + +We plan to publish on the Nextcloud app store, but in the mean time, you can use instructions at the bottom. + +## Use with Keycloak + +You can use with the [SCIM plugin we developped for keycloak](https://lab.libreho.st/libre.sh/scim/keycloak-scim). + ## Running tests To run the test, you can use [insomnia UI](https://docs.insomnia.rest). @@ -8,7 +22,16 @@ To run the test, you can use [insomnia UI](https://docs.insomnia.rest). For CI, there is still [a bug](https://github.com/Kong/insomnia/issues/4747) we need to find a fix. -## TODO +## Todo + + - ExternalID + - json exceptions + - Meta -> + - createdAt + - lastModified + - if no emails in user, return nice array + - pagination + - group member removal ## Quick "Deploy" to test @@ -19,4 +42,8 @@ unzip nextcloud-scim-main.zip rm nextcloud-scim-main.zip rm -rf scimserviceprovider mv nextcloud-scim-main scimserviceprovider -``` \ No newline at end of file +``` + +## NextGov Hackathon + +This app was started during the [Nextgov hackathon](https://eventornado.com/submission/automatic-sso-saml-sync-from-identity-provider-keycloak-through-a-well-known-protocol-scim?s=1#idea)! \ No newline at end of file From 54ce357654be8aed2e41f3c2f0df655607af676f Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Mon, 2 May 2022 13:57:29 +0000 Subject: [PATCH 09/11] Update README.md --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2bc1d04..c36b735 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ This app allows to provision users and groups in Nextcloud from a scim client. -You can see the video that shows how it works. - -![video presentation](https://hot-objects.liiib.re/meet-liiib-re-recordings/pair_2022-05-02-15-40-37.mp4) +You can see the [video](https://hot-objects.liiib.re/meet-liiib-re-recordings/pair_2022-05-02-15-40-37.mp4) that shows how it works. ## How to use @@ -46,4 +44,4 @@ mv nextcloud-scim-main scimserviceprovider ## NextGov Hackathon -This app was started during the [Nextgov hackathon](https://eventornado.com/submission/automatic-sso-saml-sync-from-identity-provider-keycloak-through-a-well-known-protocol-scim?s=1#idea)! \ No newline at end of file +This app was started during the [Nextgov hackathon](https://eventornado.com/submission/automatic-sso-saml-sync-from-identity-provider-keycloak-through-a-well-known-protocol-scim?s=1#idea)! From f420b252aea2a88b53079ce8affd333f2bef9359 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Wed, 18 May 2022 16:23:28 +0200 Subject: [PATCH 10/11] Adds psalm and Nc style check. --- .gitignore | 1 + .php-cs-fixer.cache | 1 + .php-cs-fixer.dist.php | 18 + composer.json | 16 + composer.lock | 3176 ++++++++++++++++++++++++++++++++++++++++ psalm.xml | 43 + 6 files changed, 3255 insertions(+) create mode 100644 .gitignore create mode 100644 .php-cs-fixer.cache create mode 100644 .php-cs-fixer.dist.php create mode 100644 composer.json create mode 100644 composer.lock create mode 100644 psalm.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5657f6e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +vendor \ No newline at end of file diff --git a/.php-cs-fixer.cache b/.php-cs-fixer.cache new file mode 100644 index 0000000..a5e23b1 --- /dev/null +++ b/.php-cs-fixer.cache @@ -0,0 +1 @@ +{"php":"7.3.33","version":"3.4.0:v3.4.0#47177af1cfb9dab5d1cc4daf91b7179c2efe7fad","indent":"\t","lineEnding":"\n","rules":{"encoding":true,"full_opening_tag":true,"blank_line_after_namespace":true,"braces":{"position_after_anonymous_constructs":"same","position_after_control_structures":"same","position_after_functions_and_oop_constructs":"same"},"class_definition":true,"constant_case":true,"elseif":true,"function_declaration":{"closure_function_spacing":"one"},"indentation_type":true,"line_ending":true,"lowercase_keywords":true,"method_argument_space":{"on_multiline":"ignore"},"no_break_comment":true,"no_closing_tag":true,"no_space_around_double_colon":true,"no_spaces_after_function_name":true,"no_spaces_inside_parenthesis":true,"no_trailing_whitespace":true,"no_trailing_whitespace_in_comment":true,"single_blank_line_at_eof":true,"single_class_element_per_statement":true,"single_import_per_statement":true,"single_line_after_imports":true,"switch_case_semicolon_to_colon":true,"switch_case_space":true,"visibility_required":{"elements":["property","method","const"]},"align_multiline_comment":true,"array_indentation":true,"binary_operator_spaces":{"default":"single_space"},"blank_line_after_opening_tag":true,"no_unused_imports":true},"hashes":{"appinfo\/routes.php":3044887257,"lib\/Responses\/SCIMJSONResponse.php":2876810868,"lib\/Responses\/SCIMListResponse.php":76345573,"lib\/Responses\/SCIMErrorResponse.php":1118832559,"lib\/Controller\/ASCIMGroup.php":3712028548,"lib\/Controller\/UserController.php":2528458696,"lib\/Controller\/ASCIMUser.php":430477040,"lib\/Controller\/GroupController.php":3769468563}} \ No newline at end of file diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..5bc525b --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,18 @@ +getFinder() + ->ignoreVCSIgnored(true) + ->notPath('build') + ->notPath('l10n') + ->notPath('src') + ->notPath('vendor') + ->in(__DIR__); +return $config; \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..0aba042 --- /dev/null +++ b/composer.json @@ -0,0 +1,16 @@ +{ + "require-dev": { + "vimeo/psalm": "^4.23", + "christophwurst/nextcloud": "v22.1.1", + "nextcloud/coding-standard": "^1.0" + }, + "config": { + "allow-plugins": { + "composer/package-versions-deprecated": true + } + }, + "scripts": { + "cs:check": "php-cs-fixer fix --dry-run --diff", + "cs:fix": "php-cs-fixer fix" + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..ab072a0 --- /dev/null +++ b/composer.lock @@ -0,0 +1,3176 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "e940a72a6723ebdeb32fd9bf715ddc41", + "packages": [], + "packages-dev": [ + { + "name": "amphp/amp", + "version": "v2.6.2", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1", + "ext-json": "*", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^7 | ^8 | ^9", + "psalm/phar": "^3.11@dev", + "react/promise": "^2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "files": [ + "lib/functions.php", + "lib/Internal/functions.php" + ], + "psr-4": { + "Amp\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniel Lowrey", + "email": "rdlowrey@php.net" + }, + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Bob Weinand", + "email": "bobwei9@hotmail.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A non-blocking concurrency framework for PHP applications.", + "homepage": "https://amphp.org/amp", + "keywords": [ + "async", + "asynchronous", + "awaitable", + "concurrency", + "event", + "event-loop", + "future", + "non-blocking", + "promise" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/amp/issues", + "source": "https://github.com/amphp/amp/tree/v2.6.2" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-02-20T17:52:18+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "v1.8.1", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", + "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "shasum": "" + }, + "require": { + "amphp/amp": "^2", + "php": ">=7.1" + }, + "require-dev": { + "amphp/php-cs-fixer-config": "dev-master", + "amphp/phpunit-util": "^1.4", + "friendsofphp/php-cs-fixer": "^2.3", + "jetbrains/phpstorm-stubs": "^2019.3", + "phpunit/phpunit": "^6 || ^7 || ^8", + "psalm/phar": "^3.11.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "files": [ + "lib/functions.php" + ], + "psr-4": { + "Amp\\ByteStream\\": "lib" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Aaron Piotrowski", + "email": "aaron@trowski.com" + }, + { + "name": "Niklas Keller", + "email": "me@kelunik.com" + } + ], + "description": "A stream abstraction to make working with non-blocking I/O simple.", + "homepage": "http://amphp.org/byte-stream", + "keywords": [ + "amp", + "amphp", + "async", + "io", + "non-blocking", + "stream" + ], + "support": { + "irc": "irc://irc.freenode.org/amphp", + "issues": "https://github.com/amphp/byte-stream/issues", + "source": "https://github.com/amphp/byte-stream/tree/v1.8.1" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2021-03-30T17:13:30+00:00" + }, + { + "name": "christophwurst/nextcloud", + "version": "v22.1.1", + "source": { + "type": "git", + "url": "https://github.com/ChristophWurst/nextcloud_composer.git", + "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/8bb086cd016128b5ef8353662fd1852db3248d1e", + "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e", + "shasum": "" + }, + "require": { + "php": "^7.3 || ~8.0.0", + "psr/container": "^1.0", + "psr/event-dispatcher": "^1.0", + "psr/log": "^1.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "23.0.0-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "AGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at" + } + ], + "description": "Composer package containing Nextcloud's public API (classes, interfaces)", + "support": { + "issues": "https://github.com/ChristophWurst/nextcloud_composer/issues", + "source": "https://github.com/ChristophWurst/nextcloud_composer/tree/v22.1.1" + }, + "time": "2021-11-11T14:01:42+00:00" + }, + { + "name": "composer/package-versions-deprecated", + "version": "1.11.99.5", + "source": { + "type": "git", + "url": "https://github.com/composer/package-versions-deprecated.git", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", + "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.1.0 || ^2.0", + "php": "^7 || ^8" + }, + "replace": { + "ocramius/package-versions": "1.11.99" + }, + "require-dev": { + "composer/composer": "^1.9.3 || ^2.0@dev", + "ext-zip": "^1.13", + "phpunit/phpunit": "^6.5 || ^7" + }, + "type": "composer-plugin", + "extra": { + "class": "PackageVersions\\Installer", + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "PackageVersions\\": "src/PackageVersions" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "support": { + "issues": "https://github.com/composer/package-versions-deprecated/issues", + "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-17T14:14:24+00:00" + }, + { + "name": "composer/pcre", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/1.0.1" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-01-21T20:24:37+00:00" + }, + { + "name": "composer/semver", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", + "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-04-01T19:23:25+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "2.0.5", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", + "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", + "shasum": "" + }, + "require": { + "composer/pcre": "^1", + "php": "^5.3.2 || ^7.0 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Composer\\XdebugHandler\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "John Stevenson", + "email": "john-stevenson@blueyonder.co.uk" + } + ], + "description": "Restarts a process without Xdebug.", + "keywords": [ + "Xdebug", + "performance" + ], + "support": { + "irc": "irc://irc.freenode.org/composer", + "issues": "https://github.com/composer/xdebug-handler/issues", + "source": "https://github.com/composer/xdebug-handler/tree/2.0.5" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2022-02-24T20:20:32+00:00" + }, + { + "name": "dnoegel/php-xdg-base-dir", + "version": "v0.1.1", + "source": { + "type": "git", + "url": "https://github.com/dnoegel/php-xdg-base-dir.git", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "require-dev": { + "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "XdgBaseDir\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "implementation of xdg base directory specification for php", + "support": { + "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", + "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" + }, + "time": "2019-12-04T15:06:13+00:00" + }, + { + "name": "doctrine/annotations", + "version": "1.13.2", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", + "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "shasum": "" + }, + "require": { + "doctrine/lexer": "1.*", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^6.0 || ^8.1", + "phpstan/phpstan": "^0.12.20", + "phpunit/phpunit": "^7.5 || ^8.0 || ^9.1.5", + "symfony/cache": "^4.4 || ^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Docblock Annotations Parser", + "homepage": "https://www.doctrine-project.org/projects/annotations.html", + "keywords": [ + "annotations", + "docblock", + "parser" + ], + "support": { + "issues": "https://github.com/doctrine/annotations/issues", + "source": "https://github.com/doctrine/annotations/tree/1.13.2" + }, + "time": "2021-08-05T19:00:23+00:00" + }, + { + "name": "doctrine/lexer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9.0", + "phpstan/phpstan": "^1.3", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2022-02-28T11:07:21+00:00" + }, + { + "name": "felixfbecker/advanced-json-rpc", + "version": "v3.2.1", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "shasum": "" + }, + "require": { + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", + "php": "^7.1 || ^8.0", + "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" + }, + "require-dev": { + "phpunit/phpunit": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "AdvancedJsonRpc\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "A more advanced JSONRPC implementation", + "support": { + "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", + "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" + }, + "time": "2021-06-11T22:34:44+00:00" + }, + { + "name": "felixfbecker/language-server-protocol", + "version": "v1.5.2", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", + "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/phpstan": "*", + "squizlabs/php_codesniffer": "^3.1", + "vimeo/psalm": "^4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "LanguageServerProtocol\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "ISC" + ], + "authors": [ + { + "name": "Felix Becker", + "email": "felix.b@outlook.com" + } + ], + "description": "PHP classes for the Language Server Protocol", + "keywords": [ + "language", + "microsoft", + "php", + "server" + ], + "support": { + "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", + "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + }, + "time": "2022-03-02T22:36:06+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^2.0", + "doctrine/annotations": "^1.12", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.2.5 || ^8.0", + "php-cs-fixer/diff": "^2.0", + "symfony/console": "^4.4.20 || ^5.1.3 || ^6.0", + "symfony/event-dispatcher": "^4.4.20 || ^5.0 || ^6.0", + "symfony/filesystem": "^4.4.20 || ^5.0 || ^6.0", + "symfony/finder": "^4.4.20 || ^5.0 || ^6.0", + "symfony/options-resolver": "^4.4.20 || ^5.0 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.23", + "symfony/polyfill-php81": "^1.23", + "symfony/process": "^4.4.20 || ^5.0 || ^6.0", + "symfony/stopwatch": "^4.4.20 || ^5.0 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^1.5", + "mikey179/vfsstream": "^1.6.8", + "php-coveralls/php-coveralls": "^2.5.2", + "php-cs-fixer/accessible-object": "^1.1", + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.2", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.2.1", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^1.1 || ^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5", + "phpunitgoodpractices/polyfill": "^1.5", + "phpunitgoodpractices/traits": "^1.9.1", + "symfony/phpunit-bridge": "^5.2.4 || ^6.0", + "symfony/yaml": "^4.4.20 || ^5.0 || ^6.0" + }, + "suggest": { + "ext-dom": "For handling output formats in XML", + "ext-mbstring": "For handling non-UTF8 characters." + }, + "bin": [ + "php-cs-fixer" + ], + "type": "application", + "autoload": { + "psr-4": { + "PhpCsFixer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Dariusz Rumiński", + "email": "dariusz.ruminski@gmail.com" + } + ], + "description": "A tool to automatically fix PHP code style", + "support": { + "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", + "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2021-12-11T16:25:08+00:00" + }, + { + "name": "netresearch/jsonmapper", + "version": "v4.0.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", + "squizlabs/php_codesniffer": "~3.5" + }, + "type": "library", + "autoload": { + "psr-0": { + "JsonMapper": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "OSL-3.0" + ], + "authors": [ + { + "name": "Christian Weiske", + "email": "cweiske@cweiske.de", + "homepage": "http://github.com/cweiske/jsonmapper/", + "role": "Developer" + } + ], + "description": "Map nested JSON structures onto PHP classes", + "support": { + "email": "cweiske@cweiske.de", + "issues": "https://github.com/cweiske/jsonmapper/issues", + "source": "https://github.com/cweiske/jsonmapper/tree/v4.0.0" + }, + "time": "2020-12-01T19:48:11+00:00" + }, + { + "name": "nextcloud/coding-standard", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nextcloud/coding-standard.git", + "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nextcloud/coding-standard/zipball/f3d1f9375e89c605deb1734f59a9f51ecbe80578", + "reference": "f3d1f9375e89c605deb1734f59a9f51ecbe80578", + "shasum": "" + }, + "require": { + "friendsofphp/php-cs-fixer": "^3.2", + "php": "^7.3|^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Nextcloud\\CodingStandard\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christoph Wurst", + "email": "christoph@winzerhof-wurst.at" + } + ], + "description": "Nextcloud coding standards for the php cs fixer", + "support": { + "issues": "https://github.com/nextcloud/coding-standard/issues", + "source": "https://github.com/nextcloud/coding-standard/tree/v1.0.0" + }, + "time": "2021-11-10T08:44:10+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v4.13.2", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", + "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=7.0" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + }, + "time": "2021-11-30T19:35:32+00:00" + }, + { + "name": "openlss/lib-array2xml", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nullivex/lib-array2xml.git", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "autoload": { + "psr-0": { + "LSS": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Bryan Tong", + "email": "bryan@nullivex.com", + "homepage": "https://www.nullivex.com" + }, + { + "name": "Tony Butler", + "email": "spudz76@gmail.com", + "homepage": "https://www.nullivex.com" + } + ], + "description": "Array2XML conversion library credit to lalit.org", + "homepage": "https://www.nullivex.com", + "keywords": [ + "array", + "array conversion", + "xml", + "xml conversion" + ], + "support": { + "issues": "https://github.com/nullivex/lib-array2xml/issues", + "source": "https://github.com/nullivex/lib-array2xml/tree/master" + }, + "time": "2019-03-29T20:06:56+00:00" + }, + { + "name": "php-cs-fixer/diff", + "version": "v2.0.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/diff.git", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "shasum": "" + }, + "require": { + "php": "^5.6 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", + "symfony/process": "^3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "sebastian/diff v3 backport support for PHP 5.6+", + "homepage": "https://github.com/PHP-CS-Fixer", + "keywords": [ + "diff" + ], + "support": { + "issues": "https://github.com/PHP-CS-Fixer/diff/issues", + "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + }, + "time": "2020-10-14T08:32:19+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", + "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + }, + "time": "2021-10-19T17:43:47+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "77a32518733312af16a44300404e945338981de3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", + "reference": "77a32518733312af16a44300404e945338981de3", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*", + "psalm/phar": "^4.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.6.1" + }, + "time": "2022-03-15T21:29:03+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/master" + }, + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", + "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/1.1.1" + }, + "time": "2021-03-05T17:36:06+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "sebastian/diff", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:10:38+00:00" + }, + { + "name": "symfony/console", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", + "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php73": "^1.9", + "symfony/polyfill-php80": "^1.16", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/string": "^5.1|^6.0" + }, + "conflict": { + "psr/log": ">=3", + "symfony/dependency-injection": "<4.4", + "symfony/dotenv": "<5.1", + "symfony/event-dispatcher": "<4.4", + "symfony/lock": "<4.4", + "symfony/process": "<4.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0" + }, + "require-dev": { + "psr/log": "^1|^2", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/event-dispatcher": "^4.4|^5.0|^6.0", + "symfony/lock": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/var-dumper": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-12T16:02:29+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/dependency-injection": "<4.4" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^4.4|^5.0|^6.0", + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-foundation": "^4.4|^5.0|^6.0", + "symfony/service-contracts": "^1.1|^2|^3", + "symfony/stopwatch": "^4.4|^5.0|^6.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v5.4.7", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f", + "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v5.4.7" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-01T12:33:59+00:00" + }, + { + "name": "symfony/finder", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", + "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-15T08:07:45+00:00" + }, + { + "name": "symfony/options-resolver", + "version": "v5.4.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/options-resolver.git", + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an improved replacement for the array_replace PHP function", + "homepage": "https://symfony.com", + "keywords": [ + "config", + "configuration", + "options" + ], + "support": { + "source": "https://github.com/symfony/options-resolver/tree/v5.4.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-01-02T09:53:40+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "30885182c981ab175d4d034db0f6f469898070ab" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", + "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-10-20T20:35:02+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", + "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-23T21:10:46+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", + "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", + "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-11-30T18:21:41+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", + "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php73\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-06-05T21:20:04+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-04T08:16:47+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "v1.25.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php81\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-09-13T13:58:11+00:00" + }, + { + "name": "symfony/process", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-php80": "^1.16" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-08T05:07:18+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v2.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "psr/container": "^1.1", + "symfony/deprecation-contracts": "^2.1|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "suggest": { + "symfony/service-implementation": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-03-13T20:07:29+00:00" + }, + { + "name": "symfony/stopwatch", + "version": "v5.4.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/stopwatch.git", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/service-contracts": "^1|^2|^3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Stopwatch\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a way to profile code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/stopwatch/tree/v5.4.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-02-18T16:06:09+00:00" + }, + { + "name": "symfony/string", + "version": "v5.4.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8", + "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "~1.15" + }, + "conflict": { + "symfony/translation-contracts": ">=3.0" + }, + "require-dev": { + "symfony/error-handler": "^4.4|^5.0|^6.0", + "symfony/http-client": "^4.4|^5.0|^6.0", + "symfony/translation-contracts": "^1.1|^2", + "symfony/var-exporter": "^4.4|^5.0|^6.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v5.4.8" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2022-04-19T10:40:37+00:00" + }, + { + "name": "vimeo/psalm", + "version": "4.23.0", + "source": { + "type": "git", + "url": "https://github.com/vimeo/psalm.git", + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", + "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", + "shasum": "" + }, + "require": { + "amphp/amp": "^2.4.2", + "amphp/byte-stream": "^1.5", + "composer/package-versions-deprecated": "^1.8.0", + "composer/semver": "^1.4 || ^2.0 || ^3.0", + "composer/xdebug-handler": "^1.1 || ^2.0 || ^3.0", + "dnoegel/php-xdg-base-dir": "^0.1.1", + "ext-ctype": "*", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "felixfbecker/advanced-json-rpc": "^3.0.3", + "felixfbecker/language-server-protocol": "^1.5", + "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", + "nikic/php-parser": "^4.13", + "openlss/lib-array2xml": "^1.0", + "php": "^7.1|^8", + "sebastian/diff": "^3.0 || ^4.0", + "symfony/console": "^3.4.17 || ^4.1.6 || ^5.0 || ^6.0", + "symfony/polyfill-php80": "^1.25", + "webmozart/path-util": "^2.3" + }, + "provide": { + "psalm/psalm": "self.version" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2", + "brianium/paratest": "^4.0||^6.0", + "ext-curl": "*", + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpdocumentor/reflection-docblock": "^5", + "phpmyadmin/sql-parser": "5.1.0||dev-master", + "phpspec/prophecy": ">=1.9.0", + "phpunit/phpunit": "^9.0", + "psalm/plugin-phpunit": "^0.16", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^4.3 || ^5.0 || ^6.0", + "weirdan/prophecy-shim": "^1.0 || ^2.0" + }, + "suggest": { + "ext-curl": "In order to send data to shepherd", + "ext-igbinary": "^2.0.5 is required, used to serialize caching data" + }, + "bin": [ + "psalm", + "psalm-language-server", + "psalm-plugin", + "psalm-refactor", + "psalter" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.x-dev", + "dev-3.x": "3.x-dev", + "dev-2.x": "2.x-dev", + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php", + "src/spl_object_id.php" + ], + "psr-4": { + "Psalm\\": "src/Psalm/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matthew Brown" + } + ], + "description": "A static analysis tool for finding errors in PHP applications", + "keywords": [ + "code", + "inspection", + "php" + ], + "support": { + "issues": "https://github.com/vimeo/psalm/issues", + "source": "https://github.com/vimeo/psalm/tree/4.23.0" + }, + "time": "2022-04-28T17:35:49+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + }, + { + "name": "webmozart/path-util", + "version": "2.3.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/path-util.git", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "webmozart/assert": "~1.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\PathUtil\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "A robust cross-platform utility for normalizing, comparing and modifying file paths.", + "support": { + "issues": "https://github.com/webmozart/path-util/issues", + "source": "https://github.com/webmozart/path-util/tree/2.3.0" + }, + "abandoned": "symfony/filesystem", + "time": "2015-12-17T08:42:14+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.2.0" +} diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 0000000..40c7932 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 5a5511c48005a2c9da85ff0b7a83538201743ae8 Mon Sep 17 00:00:00 2001 From: Pierre Ozoux Date: Wed, 18 May 2022 16:28:05 +0200 Subject: [PATCH 11/11] Removes copyright comments. And uncessary libs. --- appinfo/routes.php | 26 ------------ lib/Controller/ASCIMGroup.php | 43 ++----------------- lib/Controller/ASCIMUser.php | 54 +++++------------------- lib/Controller/GroupController.php | 60 +++------------------------ lib/Controller/UserController.php | 64 ++++------------------------- lib/Responses/SCIMErrorResponse.php | 17 ++++---- lib/Responses/SCIMJSONResponse.php | 4 +- lib/Responses/SCIMListResponse.php | 16 ++++---- 8 files changed, 44 insertions(+), 240 deletions(-) diff --git a/appinfo/routes.php b/appinfo/routes.php index f023c1b..20f5718 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -1,30 +1,4 @@ - * @author Christoph Wurst - * @author Joas Schilling - * @author John Molakvoæ - * @author Morris Jobke - * @author Roeland Jago Douma - * @author Tom Needham - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ return [ 'resources' => [ 'user' => ['url' => '/Users'], diff --git a/lib/Controller/ASCIMGroup.php b/lib/Controller/ASCIMGroup.php index 1ef999c..747d056 100644 --- a/lib/Controller/ASCIMGroup.php +++ b/lib/Controller/ASCIMGroup.php @@ -2,51 +2,16 @@ declare(strict_types=1); -/** - * @copyright Copyright (c) 2018 John Molakvoæ (skjnldsv) - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Georg Ehrke - * @author Joas Schilling - * @author John Molakvoæ - * @author Roeland Jago Douma - * @author Vincent Petry - * - * @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\SCIMServiceProvider\Controller; use OC\Group\Manager; use OCP\Accounts\IAccountManager; -use OCP\Accounts\PropertyDoesNotExistException; use OCP\AppFramework\ApiController; -use OCP\AppFramework\Http; -use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IGroupManager; use OCP\IRequest; use OCP\IUserManager; use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; -use OCP\AppFramework\Http\DataResponse; -use OCP\IUser; -use Psr\Log\LoggerInterface; abstract class ASCIMGroup extends ApiController { /** @var IUserManager */ @@ -103,8 +68,8 @@ abstract class ASCIMGroup extends ApiController { } return [ - 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group'], - 'id' => $groupId, + 'schemas' => ['urn:ietf:params:scim:schemas:core:2.0:Group'], + 'id' => $groupId, 'displayName' => $group->getDisplayName(), 'externalId' => '1234', // todo 'meta' => [ @@ -113,7 +78,7 @@ abstract class ASCIMGroup extends ApiController { 'created' => '2022-04-28T18:27:17.783Z', // todo 'lastModified' => '2022-04-28T18:27:17.783Z' // todo ], - 'members' => $members - ]; + 'members' => $members + ]; } } diff --git a/lib/Controller/ASCIMUser.php b/lib/Controller/ASCIMUser.php index 7c60bf5..1e8b1b3 100644 --- a/lib/Controller/ASCIMUser.php +++ b/lib/Controller/ASCIMUser.php @@ -2,48 +2,16 @@ declare(strict_types=1); -/** - * @copyright Copyright (c) 2018 John Molakvoæ (skjnldsv) - * - * @author Arthur Schiwon - * @author Christoph Wurst - * @author Georg Ehrke - * @author Joas Schilling - * @author John Molakvoæ - * @author Roeland Jago Douma - * @author Vincent Petry - * - * @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\SCIMServiceProvider\Controller; use OC\Group\Manager; use OCP\Accounts\IAccountManager; -use OCP\Accounts\PropertyDoesNotExistException; use OCP\AppFramework\ApiController; -use OCP\AppFramework\Http; -use OCP\Files\NotFoundException; use OCP\IConfig; use OCP\IGroupManager; use OCP\IRequest; use OCP\IUserManager; use OCP\IUserSession; -use OCP\L10N\IFactory; -use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; abstract class ASCIMUser extends ApiController { /** @var IUserManager */ @@ -91,27 +59,27 @@ abstract class ASCIMUser extends ApiController { $enabled = $this->config->getUserValue($targetUserObject->getUID(), 'core', 'enabled', 'true') === 'true'; return [ - 'schemas' => ["urn:ietf:params:scim:schemas:core:2.0:User"], - 'id' => $userId, + 'schemas' => ["urn:ietf:params:scim:schemas:core:2.0:User"], + 'id' => $userId, 'name' => [ 'formatted' => $targetUserObject->getDisplayName() ], - 'meta' => [ + 'meta' => [ 'resourceType' => 'User', 'location' => '/Users/' . $userId, 'created' => '2022-04-28T18:27:17.783Z', // todo 'lastModified' => '2022-04-28T18:27:17.783Z' // todo - ], - 'userName' => $userId, - 'displayName' => $targetUserObject->getDisplayName(), - 'emails' => [ // todo if no emails + ], + 'userName' => $userId, + 'displayName' => $targetUserObject->getDisplayName(), + 'emails' => [ // todo if no emails [ - 'primary' => true, - 'value' => $targetUserObject->getSystemEMailAddress() + 'primary' => true, + 'value' => $targetUserObject->getSystemEMailAddress() ] ], 'externalId' => '1234', // todo - 'active' => $enabled - ]; + 'active' => $enabled + ]; } } diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index fcad879..63fde8e 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -2,52 +2,9 @@ declare(strict_types=1); -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon - * @author Bjoern Schiessle - * @author Christoph Wurst - * @author Daniel Calviño Sánchez - * @author Daniel Kesselberg - * @author Joas Schilling - * @author John Molakvoæ - * @author Julius Härtl - * @author Lukas Reschke - * @author michag86 - * @author Mikael Hammarin - * @author Morris Jobke - * @author Robin Appelman - * @author Roeland Jago Douma - * @author Sujith Haridasan - * @author Thomas Citharel - * @author Thomas Müller - * @author Tom Needham - * @author Vincent Petry - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ namespace OCA\SCIMServiceProvider\Controller; -use InvalidArgumentException; -use OC\HintException; -use OC\KnownUser\KnownUserService; use OCP\Accounts\IAccountManager; -use OCP\AppFramework\OCS\OCSException; -use OCP\AppFramework\OCSController; use OCP\AppFramework\Http\Response; use OCP\IConfig; use OCP\IGroupManager; @@ -62,7 +19,6 @@ use OCA\SCIMServiceProvider\Responses\SCIMListResponse; use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; - class GroupController extends ASCIMGroup { /** @var IURLGenerator */ @@ -71,8 +27,6 @@ class GroupController extends ASCIMGroup { private $logger; /** @var ISecureRandom */ private $secureRandom; - /** @var KnownUserService */ - private $knownUserService; /** @var IEventDispatcher */ private $eventDispatcher; @@ -86,7 +40,6 @@ class GroupController extends ASCIMGroup { IURLGenerator $urlGenerator, LoggerInterface $logger, ISecureRandom $secureRandom, - KnownUserService $knownUserService, IEventDispatcher $eventDispatcher) { parent::__construct($appName, $request, @@ -99,7 +52,6 @@ class GroupController extends ASCIMGroup { $this->urlGenerator = $urlGenerator; $this->logger = $logger; $this->secureRandom = $secureRandom; - $this->knownUserService = $knownUserService; $this->eventDispatcher = $eventDispatcher; } @@ -138,13 +90,12 @@ class GroupController extends ASCIMGroup { * @NoCSRFRequired * * @param string $displayName - * @param array $members + * @param array $members * @return SCIMJSONResponse * @throws Exception */ - public function create( string $displayName = '', + public function create(string $displayName = '', array $members = []): SCIMJSONResponse { - $id = urlencode($displayName); // Validate name if (empty($id)) { @@ -173,13 +124,13 @@ class GroupController extends ASCIMGroup { * @NoCSRFRequired * * @param string $id - * + * * @param string $displayName - * @param array $members + * @param array $members * @return DataResponse * @throws Exception */ - public function update( string $id, + public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse { $group = $this->groupManager->get($id); @@ -214,5 +165,4 @@ class GroupController extends ASCIMGroup { $response->setStatus(204); return $response; } - } diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index f760837..a6119b3 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -2,52 +2,9 @@ declare(strict_types=1); -/** - * @copyright Copyright (c) 2016, ownCloud, Inc. - * - * @author Arthur Schiwon - * @author Bjoern Schiessle - * @author Christoph Wurst - * @author Daniel Calviño Sánchez - * @author Daniel Kesselberg - * @author Joas Schilling - * @author John Molakvoæ - * @author Julius Härtl - * @author Lukas Reschke - * @author michag86 - * @author Mikael Hammarin - * @author Morris Jobke - * @author Robin Appelman - * @author Roeland Jago Douma - * @author Sujith Haridasan - * @author Thomas Citharel - * @author Thomas Müller - * @author Tom Needham - * @author Vincent Petry - * - * @license AGPL-3.0 - * - * This code is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License, version 3, - * as published by the Free Software Foundation. - * - * 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, version 3, - * along with this program. If not, see - * - */ namespace OCA\SCIMServiceProvider\Controller; -use InvalidArgumentException; -use OC\HintException; -use OC\KnownUser\KnownUserService; use OCP\Accounts\IAccountManager; -use OCP\AppFramework\OCS\OCSException; -use OCP\AppFramework\OCSController; use OCP\AppFramework\Http\Response; use OCP\IConfig; use OCP\IGroupManager; @@ -62,7 +19,6 @@ use OCA\SCIMServiceProvider\Responses\SCIMListResponse; use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; - class UserController extends ASCIMUser { /** @var IURLGenerator */ @@ -71,8 +27,6 @@ class UserController extends ASCIMUser { private $logger; /** @var ISecureRandom */ private $secureRandom; - /** @var KnownUserService */ - private $knownUserService; /** @var IEventDispatcher */ private $eventDispatcher; @@ -86,7 +40,6 @@ class UserController extends ASCIMUser { IURLGenerator $urlGenerator, LoggerInterface $logger, ISecureRandom $secureRandom, - KnownUserService $knownUserService, IEventDispatcher $eventDispatcher) { parent::__construct($appName, $request, @@ -99,7 +52,6 @@ class UserController extends ASCIMUser { $this->urlGenerator = $urlGenerator; $this->logger = $logger; $this->secureRandom = $secureRandom; - $this->knownUserService = $knownUserService; $this->eventDispatcher = $eventDispatcher; } @@ -149,13 +101,13 @@ class UserController extends ASCIMUser { * * @param bool $active * @param string $displayName - * @param array $emails + * @param array $emails * @param string $userName * @return SCIMJSONResponse * @throws Exception */ - public function create( bool $active = true, - string $displayName = '', + public function create(bool $active = true, + string $displayName = '', array $emails = [], string $userName = ''): SCIMJSONResponse { if ($this->userManager->userExists($userName)) { @@ -165,7 +117,7 @@ class UserController extends ASCIMUser { try { $newUser = $this->userManager->createUser($userName, $this->secureRandom->generate(64)); - $this->logger->info('Successful createUser call with userid: ' . ['app' => 'SCIMServiceProvider']); + $this->logger->info('Successful createUser call with userid: ' . $userName, ['app' => 'SCIMServiceProvider']); foreach ($emails as $email) { $this->logger->error('Log email: ' . $email['value'], ['app' => 'SCIMServiceProvider']); if ($email['primary'] === true) { @@ -185,14 +137,14 @@ class UserController extends ASCIMUser { * @NoCSRFRequired * * @param string $id - * + * * @param bool $active * @param string $displayName - * @param array $emails + * @param array $emails * @return DataResponse * @throws Exception */ - public function update( string $id, + public function update(string $id, bool $active, string $displayName = '', array $emails = []): SCIMJSONResponse { @@ -209,7 +161,6 @@ class UserController extends ASCIMUser { $targetUser->setEnabled($active); } return new SCIMJSONResponse($this->getSCIMUser($id)); - } /** @@ -234,5 +185,4 @@ class UserController extends ASCIMUser { return new SCIMErrorResponse(['message' => 'Couldn\'t delete user'], 503); } } - } diff --git a/lib/Responses/SCIMErrorResponse.php b/lib/Responses/SCIMErrorResponse.php index 0614be5..ab37d42 100644 --- a/lib/Responses/SCIMErrorResponse.php +++ b/lib/Responses/SCIMErrorResponse.php @@ -3,13 +3,10 @@ namespace OCA\SCIMServiceProvider\Responses; use OCP\AppFramework\Http\Response; -use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; - - /** * Class SCIMErrorResponse - * + * */ class SCIMErrorResponse extends SCIMJSONResponse { /** @@ -26,11 +23,11 @@ class SCIMErrorResponse extends SCIMJSONResponse { */ public function render() { $message = [ - 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:Error'], - 'detail' => $this->data['message'], - 'scimType' => '', - 'status' => $this->getStatus() - ]; + 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:Error'], + 'detail' => $this->data['message'], + 'scimType' => '', + 'status' => $this->getStatus() + ]; $response = json_encode($message, JSON_UNESCAPED_SLASHES); if ($response === false) { @@ -40,4 +37,4 @@ class SCIMErrorResponse extends SCIMJSONResponse { return $response; } -} \ No newline at end of file +} diff --git a/lib/Responses/SCIMJSONResponse.php b/lib/Responses/SCIMJSONResponse.php index 62878f4..47576f9 100644 --- a/lib/Responses/SCIMJSONResponse.php +++ b/lib/Responses/SCIMJSONResponse.php @@ -6,7 +6,7 @@ use OCP\AppFramework\Http\Response; /** * Class SCIMResourceResponse - * + * */ class SCIMJSONResponse extends Response { /** @@ -46,4 +46,4 @@ class SCIMJSONResponse extends Response { return $response; } -} \ No newline at end of file +} diff --git a/lib/Responses/SCIMListResponse.php b/lib/Responses/SCIMListResponse.php index 9cc4aa2..835e6fd 100644 --- a/lib/Responses/SCIMListResponse.php +++ b/lib/Responses/SCIMListResponse.php @@ -8,7 +8,7 @@ use OCA\SCIMServiceProvider\Exceptions\SCIMException; /** * Class SCIMListResponse - * + * */ class SCIMListResponse extends Response { /** @@ -39,12 +39,12 @@ class SCIMListResponse extends Response { * @throws \Exception If data could not get encoded */ public function render() { - $scimReponse = [ - 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:ListResponse'], - 'startIndex' => 1, // todo pagination - 'Resources' => $this->data, - 'totalResults' => sizeof($this->data) - ]; + $scimReponse = [ + 'schemas' => ['urn:ietf:params:scim:api:messages:2.0:ListResponse'], + 'startIndex' => 1, // todo pagination + 'Resources' => $this->data, + 'totalResults' => sizeof($this->data) + ]; $response = json_encode($scimReponse, JSON_UNESCAPED_SLASHES); if ($response === false) { @@ -54,4 +54,4 @@ class SCIMListResponse extends Response { return $response; } -} \ No newline at end of file +}