diff --git a/.gitignore b/.gitignore index 5657f6ea7d574e423dc2c297e2e19a9dbd7a7170..0a2d0d0e8014f6e73a26a436fbefa91cd7037ef0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -vendor \ No newline at end of file +vendor +/lib/Vendor diff --git a/README.md b/README.md index 9822e8fd98e1d1db71de4c6a5ebef70b7b63be55..b2dae41754f7af1b0409b5b9a86cc38691c3fa11 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,101 @@ # SCIM Service Provider -This app allows to provision users and groups in Nextcloud from a scim client. +This app allows to provision users and groups in Nextcloud from a scim client. It is based on [audriga/scim-server-php](https://github.com/audriga/scim-server-php) SCIM library. 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. -## Limitations +--- - - doesn't accept `application/scim+json` content-type, but only `application/json` - - doesn't implement `meta:createdAt` nor `meta:lastModified` due to this [bug](https://github.com/nextcloud/server/issues/22640) (return unix epoch instead). +## Table of content + +1. [How to use](#how-to-use) + 1. [Installation](#installation) + 2. [Authentication](#authentication) + 1. [Basic authentication](#basic-authentication) + 2. [Bearer token authentication](#bearer-token-authentication) + 1. [JWT generation (for admins only!)](#jwt-generation-for-admins-only) + 2. [Usage of the JWT](#usage-of-the-jwt) +2. [Use with Keycloak](#use-with-keycloak) +3. [Use with AzureAD](#use-with-azuread) +4. [Running tests](#running-tests) +5. [Todo](#todo) +6. [Disclaimer](#disclaimer) +7. [NextGov Hackathon](#nextgov-hackathon) + +--- ## How to use -We plan to publish on the Nextcloud app store, but in the mean time, you can use instructions at the bottom. +### Installation +We plan to publish on the Nextcloud app store, but in the mean time you can use instructions bellow. + +``` +cd apps +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 +mv nextcloud-scim-main scimserviceprovider +``` + +### Authentication +Currently, this app supports both Basic authentication, as well as Bearer token authentication via JWTs. One can change between these two authentication modes by setting the `auth_type` config parameter in the config file under `/lib/Config/config.php` to either `basic` or `bearer`. + +#### Basic authentication +In order to authenticate via Basic auth, send SCIM requests to the SCIM endpoints of the following form: + +> `http:///index.php/apps/scimserviceprovider/` + +where `` designates a SCIM resource, such as `Users` or `Groups`. + +For example: + +``` +$ curl http:///index.php/apps/scimserviceprovider/ -u someusername:pass123 -H 'Content-Type: application/scim+json' +``` + +#### Bearer token authentication +In order to authenticate via a Bearer token, send SCIM requests to the SCIM endpoints of the following form: + +> `http:///index.php/apps/scimserviceprovider/bearer/` + +where `` designates a SCIM resource, such as `Users` or `Groups`. Also, make sure to provide the Bearer token in the `Authorization` header of the SCIM HTTP request. + +##### JWT generation (for admins only!) +Before providing the token, though, you'd need to obtain one. This is done with the help of a script which can generate JWTs and which is part of `scim-server-php`, the SCIM library by audriga, used as a dependency in this app. + +A JWT can be generated as follows: + +``` +$ vendor/audriga/scim-opf/bin/generate_jwt.php --username someusername --secret topsecret123 +``` + +where + +- `--username` is the username of the user that you want to generate a JWT +- `--secret` is the secret key set in the `jwt` config parameter in the config file under `/lib/Config/config.php`, used for signing the JWT + +**Note:** the generated JWT has a claim, called `user` which contains the username that was passed to the JWT generation script and which is later also used for performing the actual authentication check in Nextcloud. For example, it could look like something like this: `{"user":"someusername"}.` + +##### Usage of the JWT +A sample usage of JWT authentication as an example: + +``` +$ curl http:///index.php/apps/scimserviceprovider/ -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.Oetm7xvhkYbiItRiqNx-z7LZ6ZkmDe1z_95igbPUSjA' -H 'Content-Type: application/scim+json' +``` ## Use with Keycloak You can use with the [SCIM plugin we developped for keycloak](https://lab.libreho.st/libre.sh/scim/keycloak-scim). +## Use with AzureAD + +You can provision users from AzureAD to Nextcloud with this app. For this, you need to do the following: + +- Enable Bearer token authentication via JWTs (see [Authentication](#authentication)) +- Generate a JWT (see [JWT Generation](#jwt-generation-for-admins-only)) and provide it to AzureAD +- Finally, point AzureAD to `https:///index.php/apps/scimserviceprovider/bearer` + ## Running tests To run the test, you can use [insomnia UI](https://docs.insomnia.rest). @@ -27,10 +106,11 @@ For CI, there is still [a bug](https://github.com/Kong/insomnia/issues/4747) we ## Todo - - [ ] Meta (Create our own table) + - [ ] Meta -> ([can't implement yet](https://github.com/nextcloud/server/issues/22640)) - createdAt - lastModified - - [ ] ExternalID for Groups (Create our onw table) + - [ ] ExternalID + - [ ] Groups - [waiting for feedback](https://help.nextcloud.com/t/add-metadata-to-groups/139271) - [ ] json exceptions - [ ] group member removal - [ ] pagination @@ -39,19 +119,19 @@ For CI, there is still [a bug](https://github.com/Kong/insomnia/issues/4747) we - [ ] test psalm - [ ] test insomnia - [ ] publish app on app store - - [ ] lib user scim php - - [ ] accept first email, even if not primary + - [ ] Allow for simultaneous usage of basic auth and bearer token auth (see **Authentication TODOs / Open issues**) -## Quick "Deploy" to test +### Authentication TODOs / Open issues +#### Support for simultaneously using basic auth and bearer token auth in parallel +Solution idea: -``` -cd apps -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 -mv nextcloud-scim-main scimserviceprovider -``` +- Instead of having two different sets of endpoints which are disjunct from each other for supporting both auth types, one could add an authentication middleware which intercepts requests and checks the `Authorization` header's contents +- Depending on whether the header has as first part of its value the string `Basic` or `Bearer`, the middleware can decide which authentication logic to call for performing the authentication with the provided authentication credentials +- In case of `Bearer`, the current implementation of bearer token authentication via JWTs can be used +- In case of `Basic`, one could take a closer look at how Nextcloud performs basic authentication for API endpoints and possibly make use of methods like [checkPassword](https://github.com/nextcloud/server/blob/master/lib/private/User/Manager.php#L237) from the [Manager](https://github.com/nextcloud/server/blob/master/lib/private/User/Manager.php) class for Nextcloud users + +## Disclaimer +This app relies on the fixes, being introduced to Nextcloud in [PR #34172](https://github.com/nextcloud/server/pull/34172), since Nextcloud can't properly handle the `Content-Type` header value for SCIM (`application/scim+json`) otherwise. In the meantime until this PR is merged, SCIM clients interacting with this app might need to resort to using the standard value of `application/json` instead. ## NextGov Hackathon diff --git a/appinfo/routes.php b/appinfo/routes.php index 20f5718748996c883f0021ecb8582ad535437e0a..65f8ecdacc68b50476cfb6862343baf1105e1be3 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -1,7 +1,46 @@ [ - 'user' => ['url' => '/Users'], - 'group' => ['url' => '/Groups'] + +$routes = [ + 'routes' => [ + ['name' => 'service_provider_configuration#resource_types', 'url' => '/ResourceTypes', 'verb' => 'GET'], + ['name' => 'service_provider_configuration#schemas', 'url' => '/Schemas', 'verb' => 'GET'], + ['name' => 'service_provider_configuration#service_provider_config', 'url' => '/ServiceProviderConfig', 'verb' => 'GET'], ] ]; + +$config = require dirname(__DIR__) . '/lib/Config/config.php'; +$userAndGroupRoutes = []; + +if (isset($config['auth_type']) && !empty($config['auth_type']) && (strcmp($config['auth_type'], 'bearer') === 0)) { + $userAndGroupRoutes = [ + ['name' => 'user_bearer#index', 'url' => '/bearer/Users', 'verb' => 'GET'], + ['name' => 'user_bearer#show', 'url' => '/bearer/Users/{id}', 'verb' => 'GET'], + ['name' => 'user_bearer#create', 'url' => '/bearer/Users', 'verb' => 'POST'], + ['name' => 'user_bearer#update', 'url' => '/bearer/Users/{id}', 'verb' => 'PUT'], + ['name' => 'user_bearer#destroy', 'url' => '/bearer/Users/{id}', 'verb' => 'DELETE'], + + ['name' => 'group_bearer#index', 'url' => '/bearer/Groups', 'verb' => 'GET'], + ['name' => 'group_bearer#show', 'url' => '/bearer/Groups/{id}', 'verb' => 'GET'], + ['name' => 'group_bearer#create', 'url' => '/bearer/Groups', 'verb' => 'POST'], + ['name' => 'group_bearer#update', 'url' => '/bearer/Groups/{id}', 'verb' => 'PUT'], + ['name' => 'group_bearer#destroy', 'url' => '/bearer/Groups/{id}', 'verb' => 'DELETE'], + ]; +} else if (!isset($config['auth_type']) || empty($config['auth_type']) || (strcmp($config['auth_type'], 'basic') === 0)) { + $userAndGroupRoutes = [ + ['name' => 'user#index', 'url' => '/Users', 'verb' => 'GET'], + ['name' => 'user#show', 'url' => '/Users/{id}', 'verb' => 'GET'], + ['name' => 'user#create', 'url' => '/Users', 'verb' => 'POST'], + ['name' => 'user#update', 'url' => '/Users/{id}', 'verb' => 'PUT'], + ['name' => 'user#destroy', 'url' => '/Users/{id}', 'verb' => 'DELETE'], + + ['name' => 'group#index', 'url' => '/Groups', 'verb' => 'GET'], + ['name' => 'group#show', 'url' => '/Groups/{id}', 'verb' => 'GET'], + ['name' => 'group#create', 'url' => '/Groups', 'verb' => 'POST'], + ['name' => 'group#update', 'url' => '/Groups/{id}', 'verb' => 'PUT'], + ['name' => 'group#destroy', 'url' => '/Groups/{id}', 'verb' => 'DELETE'], + ]; +} + +$routes['routes'] = array_merge($routes['routes'], $userAndGroupRoutes); + +return $routes; diff --git a/composer.json b/composer.json index 0aba042315d056780dc9c233f0e4a0e11453b8ec..8db042952a7b03373bd119ada4687f0b06c9ef49 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,25 @@ }, "scripts": { "cs:check": "php-cs-fixer fix --dry-run --diff", - "cs:fix": "php-cs-fixer fix" + "cs:fix": "php-cs-fixer fix", + "post-install-cmd": [ + "rm -rf vendor/firebase", + "composer dump-autoload" + ], + "post-update-cmd": [ + "rm -rf vendor/firebase", + "composer dump-autoload" + ] + }, + "minimum-stability": "dev", + "repositories": { + "scim": { + "type": "vcs", + "url": "git@github.com:audriga/scim-server-php.git" + } + }, + "require": { + "audriga/scim-server-php": "dev-main", + "doctrine/lexer": "^1.2" } } diff --git a/composer.lock b/composer.lock index ab072a089f5ed22885914a7b5202c0d6ac8e415a..48b0b7a5173c2cea071bb3824cb40a139ad9f23a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,254 +4,227 @@ "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": [ + "content-hash": "64b7aba10119e669997cbca8af52bd38", + "packages": [ { - "name": "amphp/amp", - "version": "v2.6.2", + "name": "audriga/scim-server-php", + "version": "dev-main", "source": { "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb" + "url": "https://github.com/audriga/scim-server-php.git", + "reference": "18ef96044c5d547acbfa1c64081736ba212b68cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", - "reference": "9d5100cebffa729aaffecd3ad25dc5aeea4f13bb", + "url": "https://api.github.com/repos/audriga/scim-server-php/zipball/18ef96044c5d547acbfa1c64081736ba212b68cd", + "reference": "18ef96044c5d547acbfa1c64081736ba212b68cd", "shasum": "" }, "require": { - "php": ">=7.1" + "coenjacobs/mozart": "^0.7.1", + "firebase/php-jwt": "^6.3", + "illuminate/database": "^8.83", + "monolog/monolog": "^2.4", + "php": "^7.4", + "php-di/php-di": "^6.3", + "ramsey/uuid": "^4.2", + "slim/php-view": "^3.1", + "slim/psr7": "^1.5", + "slim/slim": "^4.10" }, "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" + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.6" }, + "default-branch": true, "type": "library", "extra": { - "branch-alias": { - "dev-master": "2.x-dev" + "mozart": { + "dep_namespace": "Opf\\ScimServerPhp\\", + "dep_directory": "/src/ScimServerPhp/", + "classmap_directory": "/classes/scimserverphp/", + "classmap_prefix": "ScimServerPhp_", + "packages": [ + "firebase/php-jwt" + ], + "delete_vendor_directories": true } }, "autoload": { - "files": [ - "lib/functions.php", - "lib/Internal/functions.php" - ], "psr-4": { - "Amp\\": "lib" + "Opf\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], + "scripts": { + "post-install-cmd": [ + "\"vendor/bin/mozart\" compose", + "composer dump-autoload" + ], + "post-update-cmd": [ + "\"vendor/bin/mozart\" compose", + "composer dump-autoload" + ] + }, "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" + "name": "audriga", + "email": "opensource@audriga.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" - ], + "description": "An open library for SCIM servers implementation", "support": { - "irc": "irc://irc.freenode.org/amphp", - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.2" + "source": "https://github.com/audriga/scim-server-php/tree/main", + "issues": "https://github.com/audriga/scim-server-php/issues" }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2022-02-20T17:52:18+00:00" + "time": "2023-02-02T15:48:56+00:00" }, { - "name": "amphp/byte-stream", - "version": "v1.8.1", + "name": "brick/math", + "version": "0.9.3", "source": { "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd" + "url": "https://github.com/brick/math.git", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/acbd8002b3536485c997c4e019206b3f10ca15bd", - "reference": "acbd8002b3536485c997c4e019206b3f10ca15bd", + "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae", + "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae", "shasum": "" }, "require": { - "amphp/amp": "^2", - "php": ">=7.1" + "ext-json": "*", + "php": "^7.1 || ^8.0" }, "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" + "php-coveralls/php-coveralls": "^2.2", + "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0", + "vimeo/psalm": "4.9.2" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, "autoload": { - "files": [ - "lib/functions.php" - ], "psr-4": { - "Amp\\ByteStream\\": "lib" + "Brick\\Math\\": "src/" } }, "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", + "description": "Arbitrary-precision arithmetic library", "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" + "Arbitrary-precision", + "BigInteger", + "BigRational", + "arithmetic", + "bigdecimal", + "bignum", + "brick", + "math" ], "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" + "issues": "https://github.com/brick/math/issues", + "source": "https://github.com/brick/math/tree/0.9.3" }, "funding": [ { - "url": "https://github.com/amphp", + "url": "https://github.com/BenMorel", "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/brick/math", + "type": "tidelift" } ], - "time": "2021-03-30T17:13:30+00:00" + "time": "2021-08-15T20:50:18+00:00" }, { - "name": "christophwurst/nextcloud", - "version": "v22.1.1", + "name": "coenjacobs/mozart", + "version": "0.7.1", "source": { "type": "git", - "url": "https://github.com/ChristophWurst/nextcloud_composer.git", - "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e" + "url": "https://github.com/coenjacobs/mozart.git", + "reference": "dbcdeb992d20d9c8914eef090f9a0d684bb1102c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ChristophWurst/nextcloud_composer/zipball/8bb086cd016128b5ef8353662fd1852db3248d1e", - "reference": "8bb086cd016128b5ef8353662fd1852db3248d1e", + "url": "https://api.github.com/repos/coenjacobs/mozart/zipball/dbcdeb992d20d9c8914eef090f9a0d684bb1102c", + "reference": "dbcdeb992d20d9c8914eef090f9a0d684bb1102c", "shasum": "" }, "require": { - "php": "^7.3 || ~8.0.0", - "psr/container": "^1.0", - "psr/event-dispatcher": "^1.0", - "psr/log": "^1.1" + "league/flysystem": "^1.0", + "php": "^7.3|^8.0", + "symfony/console": "^4|^5", + "symfony/finder": "^4|^5" + }, + "require-dev": { + "mheap/phpunit-github-actions-printer": "^1.4", + "phpunit/phpunit": "^8.5", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.4" }, + "bin": [ + "bin/mozart" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "23.0.0-dev" + "autoload": { + "psr-4": { + "CoenJacobs\\Mozart\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "AGPL-3.0-or-later" + "MIT" ], "authors": [ { - "name": "Christoph Wurst", - "email": "christoph@winzerhof-wurst.at" + "name": "Coen Jacobs", + "email": "coenjacobs@gmail.com" } ], - "description": "Composer package containing Nextcloud's public API (classes, interfaces)", + "description": "Composes all dependencies as a package inside a WordPress plugin", "support": { - "issues": "https://github.com/ChristophWurst/nextcloud_composer/issues", - "source": "https://github.com/ChristophWurst/nextcloud_composer/tree/v22.1.1" + "issues": "https://github.com/coenjacobs/mozart/issues", + "source": "https://github.com/coenjacobs/mozart/tree/0.7.1" }, - "time": "2021-11-11T14:01:42+00:00" + "funding": [ + { + "url": "https://github.com/coenjacobs", + "type": "github" + } + ], + "time": "2021-02-02T21:37:03+00:00" }, { - "name": "composer/package-versions-deprecated", - "version": "1.11.99.5", + "name": "doctrine/inflector", + "version": "2.1.x-dev", "source": { "type": "git", - "url": "https://github.com/composer/package-versions-deprecated.git", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d" + "url": "https://github.com/doctrine/inflector.git", + "reference": "bf265da9f831e46e646c7a01b59ee8a33f8c0365" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/package-versions-deprecated/zipball/b4f54f74ef3453349c24a845d22392cd31e65f1d", - "reference": "b4f54f74ef3453349c24a845d22392cd31e65f1d", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/bf265da9f831e46e646c7a01b59ee8a33f8c0365", + "reference": "bf265da9f831e46e646c7a01b59ee8a33f8c0365", "shasum": "" }, "require": { - "composer-plugin-api": "^1.1.0 || ^2.0", - "php": "^7 || ^8" - }, - "replace": { - "ocramius/package-versions": "1.11.99" + "php": "^7.2 || ^8.0" }, "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" - } + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" }, + "type": "library", "autoload": { "psr-4": { - "PackageVersions\\": "src/PackageVersions" + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -260,66 +233,88 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com" + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" }, { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be" + "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": "Composer plugin that provides efficient querying for installed package versions (no runtime IO)", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], "support": { - "issues": "https://github.com/composer/package-versions-deprecated/issues", - "source": "https://github.com/composer/package-versions-deprecated/tree/1.11.99.5" + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.1.x" }, "funding": [ { - "url": "https://packagist.com", + "url": "https://www.doctrine-project.org/sponsorship.html", "type": "custom" }, { - "url": "https://github.com/composer", - "type": "github" + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", "type": "tidelift" } ], - "time": "2022-01-17T14:14:24+00:00" + "time": "2023-01-15T14:40:19+00:00" }, { - "name": "composer/pcre", - "version": "1.0.1", + "name": "doctrine/lexer", + "version": "1.3.x-dev", "source": { "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560" + "url": "https://github.com/doctrine/lexer.git", + "reference": "df2c840b0bfd42b86ea60bd07d64ed57b6489539" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/67a32d7d6f9f560b726ab25a061b38ff3a80c560", - "reference": "67a32d7d6f9f560b726ab25a061b38ff3a80c560", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/df2c840b0bfd42b86ea60bd07d64ed57b6489539", + "reference": "df2c840b0bfd42b86ea60bd07d64ed57b6489539", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { + "doctrine/coding-standard": "^9 || ^10", "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^4.11 || ^5.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.x-dev" - } - }, "autoload": { "psr-4": { - "Composer\\Pcre\\": "src" + "Doctrine\\Common\\Lexer\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -328,68 +323,77 @@ ], "authors": [ { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" } ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "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": [ - "PCRE", - "preg", - "regex", - "regular expression" + "annotations", + "docblock", + "lexer", + "parser", + "php" ], "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/1.0.1" + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/1.3.x" }, "funding": [ { - "url": "https://packagist.com", + "url": "https://www.doctrine-project.org/sponsorship.html", "type": "custom" }, { - "url": "https://github.com/composer", - "type": "github" + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" }, { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", "type": "tidelift" } ], - "time": "2022-01-21T20:24:37+00:00" + "time": "2022-12-11T21:00:40+00:00" }, { - "name": "composer/semver", - "version": "3.3.2", + "name": "fig/http-message-util", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9" + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/3953f23262f2bff1919fc82183ad9acb13ff62c9", - "reference": "3953f23262f2bff1919fc82183ad9acb13ff62c9", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", "shasum": "" }, "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" + "php": "^5.3 || ^7.0 || ^8.0" }, - "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "3.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { "psr-4": { - "Composer\\Semver\\": "src" + "Fig\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -398,183 +402,172 @@ ], "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" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", "keywords": [ - "semantic", - "semver", - "validation", - "versioning" + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" ], "support": { - "irc": "irc://irc.freenode.org/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.3.2" + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.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-04-01T19:23:25+00:00" + "time": "2020-11-24T22:02:12+00:00" }, { - "name": "composer/xdebug-handler", - "version": "2.0.5", + "name": "firebase/php-jwt", + "version": "v6.3.2", "source": { "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a" + "url": "https://github.com/firebase/php-jwt.git", + "reference": "ea7dda77098b96e666c5ef382452f94841e439cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/9e36aeed4616366d2b690bdce11f71e9178c579a", - "reference": "9e36aeed4616366d2b690bdce11f71e9178c579a", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/ea7dda77098b96e666c5ef382452f94841e439cd", + "reference": "ea7dda77098b96e666c5ef382452f94841e439cd", "shasum": "" }, "require": { - "composer/pcre": "^1", - "php": "^5.3.2 || ^7.0 || ^8.0", - "psr/log": "^1 || ^2 || ^3" + "php": "^7.1||^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^4.2 || ^5.0 || ^6.0" + "guzzlehttp/guzzle": "^6.5||^7.4", + "phpspec/prophecy-phpunit": "^1.1", + "phpunit/phpunit": "^7.5||^9.5", + "psr/cache": "^1.0||^2.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" }, "type": "library", "autoload": { "psr-4": { - "Composer\\XdebugHandler\\": "src" + "Firebase\\JWT\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" } ], - "description": "Restarts a process without Xdebug.", + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", "keywords": [ - "Xdebug", - "performance" + "jwt", + "php" ], "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" + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.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-02-24T20:20:32+00:00" + "time": "2022-12-19T17:10:46+00:00" }, { - "name": "dnoegel/php-xdg-base-dir", - "version": "v0.1.1", + "name": "illuminate/collections", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" + "url": "https://github.com/illuminate/collections.git", + "reference": "705a4e1ef93cd492c45b9b3e7911cccc990a07f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", + "url": "https://api.github.com/repos/illuminate/collections/zipball/705a4e1ef93cd492c45b9b3e7911cccc990a07f4", + "reference": "705a4e1ef93cd492c45b9b3e7911cccc990a07f4", "shasum": "" }, "require": { - "php": ">=5.3.2" + "illuminate/contracts": "^8.0", + "illuminate/macroable": "^8.0", + "php": "^7.3|^8.0" }, - "require-dev": { - "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" + "suggest": { + "symfony/var-dumper": "Required to use the dump method (^5.4)." }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, "autoload": { + "files": [ + "helpers.php" + ], "psr-4": { - "XdgBaseDir\\": "src/" + "Illuminate\\Support\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "implementation of xdg base directory specification for php", + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Illuminate Collections package.", + "homepage": "https://laravel.com", "support": { - "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", - "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "time": "2019-12-04T15:06:13+00:00" + "time": "2022-06-23T15:29:49+00:00" }, { - "name": "doctrine/annotations", - "version": "1.13.2", + "name": "illuminate/container", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/doctrine/annotations.git", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08" + "url": "https://github.com/illuminate/container.git", + "reference": "14062628d05f75047c5a1360b9350028427d568e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/5b668aef16090008790395c02c893b1ba13f7e08", - "reference": "5b668aef16090008790395c02c893b1ba13f7e08", + "url": "https://api.github.com/repos/illuminate/container/zipball/14062628d05f75047c5a1360b9350028427d568e", + "reference": "14062628d05f75047c5a1360b9350028427d568e", "shasum": "" }, "require": { - "doctrine/lexer": "1.*", - "ext-tokenizer": "*", - "php": "^7.1 || ^8.0", - "psr/cache": "^1 || ^2 || ^3" + "illuminate/contracts": "^8.0", + "php": "^7.3|^8.0", + "psr/container": "^1.0" }, - "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" + "provide": { + "psr/container-implementation": "1.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" + "Illuminate\\Container\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -583,66 +576,46 @@ ], "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" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "Docblock Annotations Parser", - "homepage": "https://www.doctrine-project.org/projects/annotations.html", - "keywords": [ - "annotations", - "docblock", - "parser" - ], + "description": "The Illuminate Container package.", + "homepage": "https://laravel.com", "support": { - "issues": "https://github.com/doctrine/annotations/issues", - "source": "https://github.com/doctrine/annotations/tree/1.13.2" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "time": "2021-08-05T19:00:23+00:00" + "time": "2022-02-02T21:03:35+00:00" }, { - "name": "doctrine/lexer", - "version": "1.2.3", + "name": "illuminate/contracts", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/doctrine/lexer.git", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229" + "url": "https://github.com/illuminate/contracts.git", + "reference": "5e0fd287a1b22a6b346a9f7cd484d8cf0234585d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/lexer/zipball/c268e882d4dbdd85e36e4ad69e02dc284f89d229", - "reference": "c268e882d4dbdd85e36e4ad69e02dc284f89d229", + "url": "https://api.github.com/repos/illuminate/contracts/zipball/5e0fd287a1b22a6b346a9f7cd484d8cf0234585d", + "reference": "5e0fd287a1b22a6b346a9f7cd484d8cf0234585d", "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" + "php": "^7.3|^8.0", + "psr/container": "^1.0", + "psr/simple-cache": "^1.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, "autoload": { "psr-4": { - "Doctrine\\Common\\Lexer\\": "lib/Doctrine/Common/Lexer" + "Illuminate\\Contracts\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -651,208 +624,180 @@ ], "authors": [ { - "name": "Guilherme Blanco", - "email": "guilhermeblanco@gmail.com" - }, - { - "name": "Roman Borschel", - "email": "roman@code-factory.org" - }, - { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com" + "name": "Taylor Otwell", + "email": "taylor@laravel.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" - ], + "description": "The Illuminate Contracts package.", + "homepage": "https://laravel.com", "support": { - "issues": "https://github.com/doctrine/lexer/issues", - "source": "https://github.com/doctrine/lexer/tree/1.2.3" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "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" + "time": "2022-01-13T14:47:47+00:00" }, { - "name": "felixfbecker/advanced-json-rpc", - "version": "v3.2.1", + "name": "illuminate/database", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" + "url": "https://github.com/illuminate/database.git", + "reference": "606f2935697e94fc6a9e2eae430a7f279283f60c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", + "url": "https://api.github.com/repos/illuminate/database/zipball/606f2935697e94fc6a9e2eae430a7f279283f60c", + "reference": "606f2935697e94fc6a9e2eae430a7f279283f60c", "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" + "ext-json": "*", + "illuminate/collections": "^8.0", + "illuminate/container": "^8.0", + "illuminate/contracts": "^8.0", + "illuminate/macroable": "^8.0", + "illuminate/support": "^8.0", + "php": "^7.3|^8.0", + "symfony/console": "^5.4" }, - "require-dev": { - "phpunit/phpunit": "^7.0 || ^8.0" + "suggest": { + "doctrine/dbal": "Required to rename columns and drop SQLite columns (^2.13.3|^3.1.4).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "illuminate/console": "Required to use the database commands (^8.0).", + "illuminate/events": "Required to use the observers with Eloquent (^8.0).", + "illuminate/filesystem": "Required to use the migrations (^8.0).", + "illuminate/pagination": "Required to paginate the result set (^8.0).", + "symfony/finder": "Required to use Eloquent model factories (^5.4)." }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, "autoload": { "psr-4": { - "AdvancedJsonRpc\\": "lib/" + "Illuminate\\Database\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "ISC" + "MIT" ], "authors": [ { - "name": "Felix Becker", - "email": "felix.b@outlook.com" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "A more advanced JSONRPC implementation", + "description": "The Illuminate Database package.", + "homepage": "https://laravel.com", + "keywords": [ + "database", + "laravel", + "orm", + "sql" + ], "support": { - "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "time": "2021-06-11T22:34:44+00:00" + "time": "2022-12-19T10:24:20+00:00" }, { - "name": "felixfbecker/language-server-protocol", - "version": "v1.5.2", + "name": "illuminate/macroable", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842" + "url": "https://github.com/illuminate/macroable.git", + "reference": "aed81891a6e046fdee72edd497f822190f61c162" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/6e82196ffd7c62f7794d778ca52b69feec9f2842", - "reference": "6e82196ffd7c62f7794d778ca52b69feec9f2842", + "url": "https://api.github.com/repos/illuminate/macroable/zipball/aed81891a6e046fdee72edd497f822190f61c162", + "reference": "aed81891a6e046fdee72edd497f822190f61c162", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpstan/phpstan": "*", - "squizlabs/php_codesniffer": "^3.1", - "vimeo/psalm": "^4.0" + "php": "^7.3|^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.x-dev" + "dev-master": "8.x-dev" } }, "autoload": { "psr-4": { - "LanguageServerProtocol\\": "src/" + "Illuminate\\Support\\": "" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "ISC" + "MIT" ], "authors": [ { - "name": "Felix Becker", - "email": "felix.b@outlook.com" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "PHP classes for the Language Server Protocol", - "keywords": [ - "language", - "microsoft", - "php", - "server" - ], + "description": "The Illuminate Macroable package.", + "homepage": "https://laravel.com", "support": { - "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.2" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "time": "2022-03-02T22:36:06+00:00" + "time": "2021-11-16T13:57:03+00:00" }, { - "name": "friendsofphp/php-cs-fixer", - "version": "v3.4.0", + "name": "illuminate/support", + "version": "8.x-dev", "source": { "type": "git", - "url": "https://github.com/FriendsOfPHP/PHP-CS-Fixer.git", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad" + "url": "https://github.com/illuminate/support.git", + "reference": "7895479ee9254069462bc9aa266eff20a5d46bae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfPHP/PHP-CS-Fixer/zipball/47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", - "reference": "47177af1cfb9dab5d1cc4daf91b7179c2efe7fad", + "url": "https://api.github.com/repos/illuminate/support/zipball/7895479ee9254069462bc9aa266eff20a5d46bae", + "reference": "7895479ee9254069462bc9aa266eff20a5d46bae", "shasum": "" }, "require": { - "composer/semver": "^3.2", - "composer/xdebug-handler": "^2.0", - "doctrine/annotations": "^1.12", + "doctrine/inflector": "^1.4|^2.0", "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" + "ext-mbstring": "*", + "illuminate/collections": "^8.0", + "illuminate/contracts": "^8.0", + "illuminate/macroable": "^8.0", + "nesbot/carbon": "^2.53.1", + "php": "^7.3|^8.0", + "voku/portable-ascii": "^1.6.1" }, - "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" + "conflict": { + "tightenco/collect": "<5.5.33" }, "suggest": { - "ext-dom": "For handling output formats in XML", - "ext-mbstring": "For handling non-UTF8 characters." + "illuminate/filesystem": "Required to use the composer class (^8.0).", + "league/commonmark": "Required to use Str::markdown() and Stringable::markdown() (^1.3|^2.0.2).", + "ramsey/uuid": "Required to use Str::uuid() (^4.2.2).", + "symfony/process": "Required to use the composer class (^5.4).", + "symfony/var-dumper": "Required to use the dd function (^5.4).", + "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.4.1)." }, - "bin": [ - "php-cs-fixer" - ], - "type": "application", - "autoload": { - "psr-4": { - "PhpCsFixer\\": "src/" + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "files": [ + "helpers.php" + ], + "psr-4": { + "Illuminate\\Support\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -861,100 +806,51 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Dariusz Rumiński", - "email": "dariusz.ruminski@gmail.com" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" } ], - "description": "A tool to automatically fix PHP code style", + "description": "The Illuminate Support package.", + "homepage": "https://laravel.com", "support": { - "issues": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/issues", - "source": "https://github.com/FriendsOfPHP/PHP-CS-Fixer/tree/v3.4.0" + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" }, - "funding": [ - { - "url": "https://github.com/keradus", - "type": "github" - } - ], - "time": "2021-12-11T16:25:08+00:00" + "time": "2022-12-19T10:24:20+00:00" }, { - "name": "netresearch/jsonmapper", - "version": "v4.0.0", + "name": "laravel/serializable-closure", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d" + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "975c8239e2d8c9582fa5280cf8b9496aa717c173" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", - "reference": "8bbc021a8edb2e4a7ea2f8ad4fa9ec9dce2fcb8d", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/975c8239e2d8c9582fa5280cf8b9496aa717c173", + "reference": "975c8239e2d8c9582fa5280cf8b9496aa717c173", "shasum": "" }, "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=7.1" + "php": "^7.3|^8.0" }, "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0", - "squizlabs/php_codesniffer": "~3.5" + "nesbot/carbon": "^2.61", + "pestphp/pest": "^1.21.3", + "phpstan/phpstan": "^1.8.2", + "symfony/var-dumper": "^5.4.11" }, + "default-branch": true, "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" + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" } - ], - "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" + "Laravel\\SerializableClosure\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -963,204 +859,336 @@ ], "authors": [ { - "name": "Christoph Wurst", - "email": "christoph@winzerhof-wurst.at" + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" } ], - "description": "Nextcloud coding standards for the php cs fixer", + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], "support": { - "issues": "https://github.com/nextcloud/coding-standard/issues", - "source": "https://github.com/nextcloud/coding-standard/tree/v1.0.0" + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" }, - "time": "2021-11-10T08:44:10+00:00" + "time": "2022-12-28T12:34:46+00:00" }, { - "name": "nikic/php-parser", - "version": "v4.13.2", + "name": "league/flysystem", + "version": "1.x-dev", "source": { "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077" + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/210577fe3cf7badcc5814d99455df46564f3c077", - "reference": "210577fe3cf7badcc5814d99455df46564f3c077", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/3239285c825c152bcc315fe0e87d6b55f5972ed1", + "reference": "3239285c825c152bcc315fe0e87d6b55f5972ed1", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": ">=7.0" + "ext-fileinfo": "*", + "league/mime-type-detection": "^1.3", + "php": "^7.2.5 || ^8.0" + }, + "conflict": { + "league/flysystem-sftp": "<1.0.6" }, "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpspec/prophecy": "^1.11.1", + "phpunit/phpunit": "^8.5.8" + }, + "suggest": { + "ext-ftp": "Allows you to use FTP server storage", + "ext-openssl": "Allows you to use FTPS server storage", + "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", + "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", + "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", + "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", + "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", + "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", + "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", + "league/flysystem-webdav": "Allows you to use WebDAV storage", + "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter", + "spatie/flysystem-dropbox": "Allows you to use Dropbox storage", + "srmklive/flysystem-dropbox-v2": "Allows you to use Dropbox storage for PHP 5 applications" }, - "bin": [ - "bin/php-parse" - ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "1.1-dev" } }, "autoload": { "psr-4": { - "PhpParser\\": "lib/PhpParser" + "League\\Flysystem\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Nikita Popov" + "name": "Frank de Jonge", + "email": "info@frenky.net" } ], - "description": "A PHP parser written in PHP", + "description": "Filesystem abstraction: Many filesystems, one API.", "keywords": [ - "parser", - "php" + "Cloud Files", + "WebDAV", + "abstraction", + "aws", + "cloud", + "copy.com", + "dropbox", + "file systems", + "files", + "filesystem", + "filesystems", + "ftp", + "rackspace", + "remote", + "s3", + "sftp", + "storage" ], "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.13.2" + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/1.x" }, - "time": "2021-11-30T19:35:32+00:00" + "funding": [ + { + "url": "https://offset.earth/frankdejonge", + "type": "other" + } + ], + "time": "2022-10-04T09:16:37+00:00" }, { - "name": "openlss/lib-array2xml", - "version": "1.0.0", + "name": "league/mime-type-detection", + "version": "1.11.0", "source": { "type": "git", - "url": "https://github.com/nullivex/lib-array2xml.git", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90" + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nullivex/lib-array2xml/zipball/a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", - "reference": "a91f18a8dfc69ffabe5f9b068bc39bb202c81d90", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ff6248ea87a9f116e78edd6002e39e5128a0d4dd", + "reference": "ff6248ea87a9f116e78edd6002e39e5128a0d4dd", "shasum": "" }, "require": { - "php": ">=5.3.2" + "ext-fileinfo": "*", + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3" }, "type": "library", "autoload": { - "psr-0": { - "LSS": "" + "psr-4": { + "League\\MimeTypeDetection\\": "src" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache-2.0" + "MIT" ], "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" + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" } ], - "description": "Array2XML conversion library credit to lalit.org", - "homepage": "https://www.nullivex.com", - "keywords": [ - "array", - "array conversion", - "xml", - "xml conversion" - ], + "description": "Mime-type detection for Flysystem", "support": { - "issues": "https://github.com/nullivex/lib-array2xml/issues", - "source": "https://github.com/nullivex/lib-array2xml/tree/master" + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.11.0" }, - "time": "2019-03-29T20:06:56+00:00" + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2022-04-17T13:12:02+00:00" }, { - "name": "php-cs-fixer/diff", - "version": "v2.0.2", + "name": "monolog/monolog", + "version": "2.x-dev", "source": { "type": "git", - "url": "https://github.com/PHP-CS-Fixer/diff.git", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3" + "url": "https://github.com/Seldaek/monolog.git", + "reference": "1387e02612584ffa1a9e93384d2d63ba0a747e11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/diff/zipball/29dc0d507e838c4580d018bd8b5cb412474f7ec3", - "reference": "29dc0d507e838c4580d018bd8b5cb412474f7ec3", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/1387e02612584ffa1a9e93384d2d63ba0a747e11", + "reference": "1387e02612584ffa1a9e93384d2d63ba0a747e11", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0 || ^8.0" + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" }, "require-dev": { - "phpunit/phpunit": "^5.7.23 || ^6.4.3 || ^7.0", - "symfony/process": "^3.3" + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Monolog\\": "src/Monolog" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" } ], - "description": "sebastian/diff v3 backport support for PHP 5.6+", - "homepage": "https://github.com/PHP-CS-Fixer", + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", "keywords": [ - "diff" + "log", + "logging", + "psr-3" ], "support": { - "issues": "https://github.com/PHP-CS-Fixer/diff/issues", - "source": "https://github.com/PHP-CS-Fixer/diff/tree/v2.0.2" + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.x" }, - "time": "2020-10-14T08:32:19+00:00" + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2022-10-14T15:01:04+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", + "name": "nesbot/carbon", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + "url": "https://github.com/briannesbitt/Carbon.git", + "reference": "09acf64155c16dc6f580f36569ae89344e9734a3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/09acf64155c16dc6f580f36569ae89344e9734a3", + "reference": "09acf64155c16dc6f580f36569ae89344e9734a3", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0" + "ext-json": "*", + "php": "^7.1.8 || ^8.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation": "^3.4 || ^4.0 || ^5.0 || ^6.0" }, + "require-dev": { + "doctrine/dbal": "^2.0 || ^3.1.4", + "doctrine/orm": "^2.7", + "friendsofphp/php-cs-fixer": "^3.0", + "kylekatarnls/multi-tester": "^2.0", + "ondrejmirtes/better-reflection": "*", + "phpmd/phpmd": "^2.9", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12.99 || ^1.7.14", + "phpunit/php-file-iterator": "^2.0.5 || ^3.0.6", + "phpunit/phpunit": "^7.5.20 || ^8.5.26 || ^9.5.20", + "squizlabs/php_codesniffer": "^3.4" + }, + "default-branch": true, + "bin": [ + "bin/carbon" + ], "type": "library", "extra": { "branch-alias": { - "dev-2.x": "2.x-dev" + "dev-3.x": "3.x-dev", + "dev-master": "2.x-dev" + }, + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src/" + "Carbon\\": "src/Carbon/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1169,197 +1197,282 @@ ], "authors": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" + "date", + "datetime", + "time" ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/briannesbitt/Carbon/issues", + "source": "https://github.com/briannesbitt/Carbon" }, - "time": "2020-06-27T09:03:43+00:00" + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2023-01-06T15:55:01+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "5.3.0", + "name": "nikic/fast-route", + "version": "v1.x-dev", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170" + "url": "https://github.com/nikic/FastRoute.git", + "reference": "4012884e0b916e1bd895a5061d4abc3c99e283a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/622548b623e81ca6d78b721c5e029f4ce664f170", - "reference": "622548b623e81ca6d78b721c5e029f4ce664f170", + "url": "https://api.github.com/repos/nikic/FastRoute/zipball/4012884e0b916e1bd895a5061d4abc3c99e283a4", + "reference": "4012884e0b916e1bd895a5061d4abc3c99e283a4", "shasum": "" }, "require": { - "ext-filter": "*", - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.3", - "webmozart/assert": "^1.9.1" + "php": ">=5.4.0" }, "require-dev": { - "mockery/mockery": "~1.3.2", - "psalm/phar": "^4.8" + "phpunit/phpunit": "^4.8.35|~5.7" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "FastRoute\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "account@ijaap.nl" + "name": "Nikita Popov", + "email": "nikic@php.net" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "description": "Fast request router for PHP", + "keywords": [ + "router", + "routing" + ], "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.3.0" + "issues": "https://github.com/nikic/FastRoute/issues", + "source": "https://github.com/nikic/FastRoute/tree/v1.x" }, - "time": "2021-10-19T17:43:47+00:00" + "time": "2019-12-20T12:15:33+00:00" }, { - "name": "phpdocumentor/type-resolver", - "version": "1.6.1", + "name": "php-di/invoker", + "version": "2.3.3", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "77a32518733312af16a44300404e945338981de3" + "url": "https://github.com/PHP-DI/Invoker.git", + "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/77a32518733312af16a44300404e945338981de3", - "reference": "77a32518733312af16a44300404e945338981de3", + "url": "https://api.github.com/repos/PHP-DI/Invoker/zipball/cd6d9f267d1a3474bdddf1be1da079f01b942786", + "reference": "cd6d9f267d1a3474bdddf1be1da079f01b942786", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "phpdocumentor/reflection-common": "^2.0" + "php": ">=7.3", + "psr/container": "^1.0|^2.0" }, "require-dev": { - "ext-tokenizer": "*", - "psalm/phar": "^4.8" + "athletic/athletic": "~0.1.8", + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^9.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": "src" + "Invoker\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } + "description": "Generic and extensible callable invoker", + "homepage": "https://github.com/PHP-DI/Invoker", + "keywords": [ + "callable", + "dependency", + "dependency-injection", + "injection", + "invoke", + "invoker" ], - "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" + "issues": "https://github.com/PHP-DI/Invoker/issues", + "source": "https://github.com/PHP-DI/Invoker/tree/2.3.3" }, - "time": "2022-03-15T21:29:03+00:00" + "funding": [ + { + "url": "https://github.com/mnapoli", + "type": "github" + } + ], + "time": "2021-12-13T09:22:56+00:00" }, { - "name": "psr/cache", - "version": "1.0.1", + "name": "php-di/php-di", + "version": "6.4.x-dev", "source": { "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + "url": "https://github.com/PHP-DI/PHP-DI.git", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", - "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "url": "https://api.github.com/repos/PHP-DI/PHP-DI/zipball/ae0f1b3b03d8b29dff81747063cbfd6276246cc4", + "reference": "ae0f1b3b03d8b29dff81747063cbfd6276246cc4", "shasum": "" }, "require": { - "php": ">=5.3.0" + "laravel/serializable-closure": "^1.0", + "php": ">=7.4.0", + "php-di/invoker": "^2.0", + "php-di/phpdoc-reader": "^2.0.1", + "psr/container": "^1.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "provide": { + "psr/container-implementation": "^1.0" }, + "require-dev": { + "doctrine/annotations": "~1.10", + "friendsofphp/php-cs-fixer": "^2.4", + "mnapoli/phpunit-easymock": "^1.2", + "ocramius/proxy-manager": "^2.11.2", + "phpstan/phpstan": "^0.12", + "phpunit/phpunit": "^9.5" + }, + "suggest": { + "doctrine/annotations": "Install it if you want to use annotations (version ~1.2)", + "ocramius/proxy-manager": "Install it if you want to use lazy injection (version ~2.0)" + }, + "type": "library", "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "Psr\\Cache\\": "src/" + "DI\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ + "description": "The dependency injection container for humans", + "homepage": "https://php-di.org/", + "keywords": [ + "PSR-11", + "container", + "container-interop", + "dependency injection", + "di", + "ioc", + "psr11" + ], + "support": { + "issues": "https://github.com/PHP-DI/PHP-DI/issues", + "source": "https://github.com/PHP-DI/PHP-DI/tree/6.4.0" + }, + "funding": [ { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "url": "https://github.com/mnapoli", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/php-di/php-di", + "type": "tidelift" } ], - "description": "Common interface for caching libraries", + "time": "2022-04-09T16:46:38+00:00" + }, + { + "name": "php-di/phpdoc-reader", + "version": "2.2.1", + "source": { + "type": "git", + "url": "https://github.com/PHP-DI/PhpDocReader.git", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-DI/PhpDocReader/zipball/66daff34cbd2627740ffec9469ffbac9f8c8185c", + "reference": "66daff34cbd2627740ffec9469ffbac9f8c8185c", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "require-dev": { + "mnapoli/hard-mode": "~0.3.0", + "phpunit/phpunit": "^8.5|^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpDocReader\\": "src/PhpDocReader" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PhpDocReader parses @var and @param values in PHP docblocks (supports namespaced class names with the same resolution rules as PHP)", "keywords": [ - "cache", - "psr", - "psr-6" + "phpdoc", + "reflection" ], "support": { - "source": "https://github.com/php-fig/cache/tree/master" + "issues": "https://github.com/PHP-DI/PhpDocReader/issues", + "source": "https://github.com/PHP-DI/PhpDocReader/tree/2.2.1" }, - "time": "2016-08-06T20:24:11+00:00" + "time": "2020-10-12T12:39:22+00:00" }, { "name": "psr/container", - "version": "1.1.1", + "version": "1.x-dev", "source": { "type": "git", "url": "https://github.com/php-fig/container.git", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf" + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/8622567409010282b7aeebe4bb841fe98b58dcaf", - "reference": "8622567409010282b7aeebe4bb841fe98b58dcaf", + "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea", + "reference": "513e0666f7216c7459170d56df27dfcefe1689ea", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.4.0" }, "type": "library", "autoload": { @@ -1388,27 +1501,29 @@ ], "support": { "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/1.1.1" + "source": "https://github.com/php-fig/container/tree/1.1.2" }, - "time": "2021-03-05T17:36:06+00:00" + "time": "2021-11-05T16:50:12+00:00" }, { - "name": "psr/event-dispatcher", - "version": "1.0.0", + "name": "psr/http-factory", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + "url": "https://github.com/php-fig/http-factory.git", + "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/5a4f141ac2e5bc35e615134f127e1833158d2944", + "reference": "5a4f141ac2e5bc35e615134f127e1833158d2944", "shasum": "" }, "require": { - "php": ">=7.2.0" + "php": ">=7.0.0", + "psr/http-message": "^1.0" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { @@ -1417,7 +1532,7 @@ }, "autoload": { "psr-4": { - "Psr\\EventDispatcher\\": "src/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1427,47 +1542,52 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" + "homepage": "https://www.php-fig.org/" } ], - "description": "Standard interfaces for event handling.", + "description": "Common interfaces for PSR-7 HTTP message factories", "keywords": [ - "events", + "factory", + "http", + "message", "psr", - "psr-14" + "psr-17", + "psr-7", + "request", + "response" ], "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + "source": "https://github.com/php-fig/http-factory/tree/master" }, - "time": "2019-01-08T18:20:26+00:00" + "time": "2022-07-14T07:21:53+00:00" }, { - "name": "psr/log", - "version": "1.1.4", + "name": "psr/http-message", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + "url": "https://github.com/php-fig/http-message.git", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", - "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", + "reference": "efd67d1dc14a7ef4fc4e518e7dee91c271d524e4", "shasum": "" }, "require": { "php": ">=5.3.0" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\Http\\Message\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1477,144 +1597,111 @@ "authors": [ { "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" + "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", "keywords": [ - "log", + "http", + "http-message", "psr", - "psr-3" + "psr-7", + "request", + "response" ], "support": { - "source": "https://github.com/php-fig/log/tree/1.1.4" + "source": "https://github.com/php-fig/http-message/tree/master" }, - "time": "2021-05-03T11:20:27+00:00" + "time": "2019-08-29T13:16:46+00:00" }, { - "name": "sebastian/diff", - "version": "4.0.4", + "name": "psr/http-server-handler", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "url": "https://github.com/php-fig/http-server-handler.git", + "reference": "cada5cd1c6a9871031e07f26d0f7b08c9de19039" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/php-fig/http-server-handler/zipball/cada5cd1c6a9871031e07f26d0f7b08c9de19039", + "reference": "cada5cd1c6a9871031e07f26d0f7b08c9de19039", "shasum": "" }, "require": { - "php": ">=7.3" - }, - "require-dev": { - "phpunit/phpunit": "^9.3", - "symfony/process": "^4.2 || ^5" + "php": ">=7.0", + "psr/http-message": "^1.0" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-master": "4.0-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Psr\\Http\\Server\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", + "description": "Common interface for HTTP server-side request handler", "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" + "handler", + "http", + "http-interop", + "psr", + "psr-15", + "psr-7", + "request", + "response", + "server" ], "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/php-fig/http-server-handler/tree/master" }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2020-09-17T16:52:43+00:00" }, { - "name": "symfony/console", - "version": "v5.4.8", + "name": "psr/http-server-middleware", + "version": "dev-master", "source": { "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b" + "url": "https://github.com/php-fig/http-server-middleware.git", + "reference": "adcb26d2fb28018fea3319d0035e46e8d08eb8c8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", - "reference": "ffe3aed36c4d60da2cf1b0a1cee6b8f2e5fa881b", + "url": "https://api.github.com/repos/php-fig/http-server-middleware/zipball/adcb26d2fb28018fea3319d0035e46e8d08eb8c8", + "reference": "adcb26d2fb28018fea3319d0035e46e8d08eb8c8", "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": "" + "php": ">=7.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0" }, + "default-branch": true, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Psr\\Http\\Server\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1622,156 +1709,153 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", + "description": "Common interface for HTTP server-side middleware", "keywords": [ - "cli", - "command line", - "console", - "terminal" + "http", + "http-interop", + "middleware", + "psr", + "psr-15", + "psr-7", + "request", + "response" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.8" + "issues": "https://github.com/php-fig/http-server-middleware/issues", + "source": "https://github.com/php-fig/http-server-middleware/tree/master" }, - "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" + "time": "2020-09-17T16:41:19+00:00" }, { - "name": "symfony/deprecation-contracts", - "version": "v2.5.1", + "name": "psr/log", + "version": "1.1.4", "source": { "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=5.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" - }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "dev-master": "1.1.x-dev" } }, "autoload": { - "files": [ - "function.php" - ] - }, + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" } ], - "description": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.1" + "source": "https://github.com/php-fig/log/tree/1.1.4" }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, + "time": "2021-05-03T11:20:27+00:00" + }, + { + "name": "psr/simple-cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "time": "2022-01-02T09:53:40+00:00" + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/master" + }, + "time": "2017-10-23T01:57:42+00:00" }, { - "name": "symfony/event-dispatcher", - "version": "v5.4.3", + "name": "ralouphie/getallheaders", + "version": "3.0.3", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d" + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/dec8a9f58d20df252b9cd89f1c6c1530f747685d", - "reference": "dec8a9f58d20df252b9cd89f1c6c1530f747685d", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", "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" + "php": ">=5.6" }, "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": "" + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" }, "type": "library", "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" + "files": [ + "src/getallheaders.php" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1780,69 +1864,69 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" } ], - "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", + "description": "A polyfill for getallheaders.", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.3" + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" }, - "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" + "time": "2019-03-08T08:55:37+00:00" }, { - "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.1", + "name": "ramsey/collection", + "version": "1.3.0", "source": { "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + "url": "https://github.com/ramsey/collection.git", + "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "url": "https://api.github.com/repos/ramsey/collection/zipball/ad7475d1c9e70b190ecffc58f2d989416af339b4", + "reference": "ad7475d1c9e70b190ecffc58f2d989416af339b4", "shasum": "" }, "require": { - "php": ">=7.2.5", - "psr/event-dispatcher": "^1" + "php": "^7.4 || ^8.0", + "symfony/polyfill-php81": "^1.23" }, - "suggest": { - "symfony/event-dispatcher-implementation": "" + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.28.3", + "fakerphp/faker": "^1.21", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^1.0", + "mockery/mockery": "^1.5", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3", + "phpcsstandards/phpcsutils": "^1.0.0-rc1", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.9", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5", + "psalm/plugin-mockery": "^1.1", + "psalm/plugin-phpunit": "^0.18.4", + "ramsey/coding-standard": "^2.0.3", + "ramsey/conventional-commits": "^1.3", + "vimeo/psalm": "^5.4" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "2.5-dev" + "captainhook": { + "force-install": true }, - "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" } }, "autoload": { "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" + "Ramsey\\Collection\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1851,134 +1935,163 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" } ], - "description": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", + "description": "A PHP library for representing and manipulating collections.", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "array", + "collection", + "hash", + "map", + "queue", + "set" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.1" + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/1.3.0" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/ramsey", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/ramsey/collection", "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-12-27T19:12:24+00:00" }, { - "name": "symfony/filesystem", - "version": "v5.4.7", + "name": "ramsey/uuid", + "version": "4.2.3", "source": { "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f" + "url": "https://github.com/ramsey/uuid.git", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/3a4442138d80c9f7b600fb297534ac718b61d37f", - "reference": "3a4442138d80c9f7b600fb297534ac718b61d37f", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", + "reference": "fc9bb7fb5388691fd7373cd44dcb4d63bbcf24df", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", - "symfony/polyfill-php80": "^1.16" + "brick/math": "^0.8 || ^0.9", + "ext-json": "*", + "php": "^7.2 || ^8.0", + "ramsey/collection": "^1.0", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-php80": "^1.14" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.10", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", + "doctrine/annotations": "^1.8", + "ergebnis/composer-normalize": "^2.15", + "mockery/mockery": "^1.3", + "moontoast/math": "^1.1", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.2", + "php-mock/php-mock-mockery": "^1.3", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpbench/phpbench": "^1.0", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-mockery": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^8.5 || ^9", + "slevomat/coding-standard": "^7.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.9" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-ctype": "Enables faster processing of character classification using ctype functions.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.x-dev" + }, + "captainhook": { + "force-install": true + } + }, "autoload": { + "files": [ + "src/functions.php" + ], "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Ramsey\\Uuid\\": "src/" + } }, "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": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" ], - "description": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v5.4.7" + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.2.3" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/ramsey", "type": "github" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "url": "https://tidelift.com/funding/github/packagist/ramsey/uuid", "type": "tidelift" } ], - "time": "2022-04-01T12:33:59+00:00" + "time": "2021-09-25T23:10:38+00:00" }, { - "name": "symfony/finder", - "version": "v5.4.8", + "name": "slim/php-view", + "version": "3.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9" + "url": "https://github.com/slimphp/PHP-View.git", + "reference": "94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/9b630f3427f3ebe7cd346c277a1408b00249dad9", - "reference": "9b630f3427f3ebe7cd346c277a1408b00249dad9", + "url": "https://api.github.com/repos/slimphp/PHP-View/zipball/94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7", + "reference": "94cf4224f9a47b9d51d87b4450e5c0c2595ad0c7", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php80": "^1.16" + "php": "^7.4 || ^8.0", + "psr/http-message": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.5", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.7" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Slim\\Views\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -1986,63 +2099,68 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Glenn Eggleton", + "email": "geggleto@gmail.com" } ], - "description": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", + "description": "Render PHP view scripts into a PSR-7 Response object.", + "keywords": [ + "framework", + "php", + "phtml", + "renderer", + "slim", + "template", + "view" + ], "support": { - "source": "https://github.com/symfony/finder/tree/v5.4.8" + "issues": "https://github.com/slimphp/PHP-View/issues", + "source": "https://github.com/slimphp/PHP-View/tree/3.x" }, - "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" + "time": "2022-12-01T16:27:12+00:00" }, { - "name": "symfony/options-resolver", - "version": "v5.4.3", + "name": "slim/psr7", + "version": "1.6", "source": { "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8" + "url": "https://github.com/slimphp/Slim-Psr7.git", + "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/cc1147cb11af1b43f503ac18f31aa3bec213aba8", - "reference": "cc1147cb11af1b43f503ac18f31aa3bec213aba8", + "url": "https://api.github.com/repos/slimphp/Slim-Psr7/zipball/3471c22c1a0d26c51c78f6aeb06489d38cf46a4d", + "reference": "3471c22c1a0d26c51c78f6aeb06489d38cf46a4d", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", - "symfony/polyfill-php73": "~1.0", - "symfony/polyfill-php80": "^1.16" + "fig/http-message-util": "^1.1.5", + "php": "^7.4 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "ralouphie/getallheaders": "^3.0", + "symfony/polyfill-php80": "^1.26" }, - "type": "library", - "autoload": { + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.3", + "ext-json": "*", + "http-interop/http-factory-tests": "^0.9.0", + "php-http/psr7-integration-tests": "dev-master", + "phpspec/prophecy": "^1.15", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/phpstan": "^1.8", + "phpunit/phpunit": "^9.5", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] + "Slim\\Psr7\\": "src" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2050,80 +2168,212 @@ ], "authors": [ { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "http://joshlockhart.com" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" + }, + { + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" } ], - "description": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", + "description": "Strict PSR-7 implementation", + "homepage": "https://www.slimframework.com", "keywords": [ - "config", - "configuration", - "options" + "http", + "psr-7", + "psr7" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v5.4.3" + "issues": "https://github.com/slimphp/Slim-Psr7/issues", + "source": "https://github.com/slimphp/Slim-Psr7/tree/1.6" }, - "funding": [ + "time": "2022-11-05T18:50:24+00:00" + }, + { + "name": "slim/slim", + "version": "4.x-dev", + "source": { + "type": "git", + "url": "https://github.com/slimphp/Slim.git", + "reference": "a44d0a70d49ae86d1177503b7d734303d30ea9a6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slimphp/Slim/zipball/a44d0a70d49ae86d1177503b7d734303d30ea9a6", + "reference": "a44d0a70d49ae86d1177503b7d734303d30ea9a6", + "shasum": "" + }, + "require": { + "ext-json": "*", + "nikic/fast-route": "^1.3", + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.0", + "psr/http-server-handler": "^1.0", + "psr/http-server-middleware": "^1.0", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "adriansuter/php-autoload-override": "^1.4", + "ext-simplexml": "*", + "guzzlehttp/psr7": "^2.4", + "httpsoft/http-message": "^1.0", + "httpsoft/http-server-request": "^1.0", + "laminas/laminas-diactoros": "^2.17", + "nyholm/psr7": "^1.5", + "nyholm/psr7-server": "^1.0", + "phpspec/prophecy": "^1.16", + "phpspec/prophecy-phpunit": "^2.0", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.5", + "slim/http": "^1.3", + "slim/psr7": "^1.6", + "squizlabs/php_codesniffer": "^3.7" + }, + "suggest": { + "ext-simplexml": "Needed to support XML format in BodyParsingMiddleware", + "ext-xml": "Needed to support XML format in BodyParsingMiddleware", + "php-di/php-di": "PHP-DI is the recommended container library to be used with Slim", + "slim/psr7": "Slim PSR-7 implementation. See https://www.slimframework.com/docs/v4/start/installation.html for more information." + }, + "default-branch": true, + "type": "library", + "autoload": { + "psr-4": { + "Slim\\": "Slim" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" + "name": "Josh Lockhart", + "email": "hello@joshlockhart.com", + "homepage": "https://joshlockhart.com" }, { - "url": "https://github.com/fabpot", - "type": "github" + "name": "Andrew Smith", + "email": "a.smith@silentworks.co.uk", + "homepage": "http://silentworks.co.uk" }, { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "name": "Rob Allen", + "email": "rob@akrabat.com", + "homepage": "http://akrabat.com" + }, + { + "name": "Pierre Berube", + "email": "pierre@lgse.com", + "homepage": "http://www.lgse.com" + }, + { + "name": "Gabriel Manricks", + "email": "gmanricks@me.com", + "homepage": "http://gabrielmanricks.com" + } + ], + "description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs", + "homepage": "https://www.slimframework.com", + "keywords": [ + "api", + "framework", + "micro", + "router" + ], + "support": { + "docs": "https://www.slimframework.com/docs/v4/", + "forum": "https://discourse.slimframework.com/", + "irc": "irc://irc.freenode.net:6667/slimphp", + "issues": "https://github.com/slimphp/Slim/issues", + "rss": "https://www.slimframework.com/blog/feed.rss", + "slack": "https://slimphp.slack.com/", + "source": "https://github.com/slimphp/Slim", + "wiki": "https://github.com/slimphp/Slim/wiki" + }, + "funding": [ + { + "url": "https://opencollective.com/slimphp", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slim/slim", "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-12-01T16:30:46+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.25.0", + "name": "symfony/console", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "30885182c981ab175d4d034db0f6f469898070ab" + "url": "https://github.com/symfony/console.git", + "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/30885182c981ab175d4d034db0f6f469898070ab", - "reference": "30885182c981ab175d4d034db0f6f469898070ab", + "url": "https://api.github.com/repos/symfony/console/zipball/dccb8d251a9017d5994c988b034d3e18aaabf740", + "reference": "dccb8d251a9017d5994c988b034d3e18aaabf740", "shasum": "" }, "require": { - "php": ">=7.1" + "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": { - "ext-ctype": "*" + "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": { - "ext-ctype": "For best performance" + "psr/log": "For using the console logger", + "symfony/event-dispatcher": "", + "symfony/lock": "", + "symfony/process": "" }, "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\\": "" - } + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2131,24 +2381,24 @@ ], "authors": [ { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Eases the creation of beautiful and testable command line interfaces", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" + "cli", + "command line", + "console", + "terminal" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.25.0" + "source": "https://github.com/symfony/console/tree/5.4" }, "funding": [ { @@ -2164,45 +2414,39 @@ "type": "tidelift" } ], - "time": "2021-10-20T20:35:02+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.25.0", + "name": "symfony/deprecation-contracts", + "version": "2.5.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/81b86b50cf841a64252b439e738e97f4a34e2783", - "reference": "81b86b50cf841a64252b439e738e97f4a34e2783", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { "php": ">=7.1" }, - "suggest": { - "ext-intl": "For best performance" - }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "2.5-dev" }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } + "function.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2218,18 +2462,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's grapheme_* functions", + "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.25.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/2.5" }, "funding": [ { @@ -2245,47 +2481,34 @@ "type": "tidelift" } ], - "time": "2021-11-23T21:10:46+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.25.0", + "name": "symfony/finder", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8" + "url": "https://github.com/symfony/finder.git", + "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/8590a5f561694770bdcd3f9b5c69dde6945028e8", - "reference": "8590a5f561694770bdcd3f9b5c69dde6945028e8", + "url": "https://api.github.com/repos/symfony/finder/zipball/6071aebf810ad13fe8200c224f36103abb37cf1f", + "reference": "6071aebf810ad13fe8200c224f36103abb37cf1f", "shasum": "" }, "require": { - "php": ">=7.1" - }, - "suggest": { - "ext-intl": "For best performance" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php80": "^1.16" }, "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\\": "" + "Symfony\\Component\\Finder\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2294,26 +2517,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for intl's Normalizer class and related functions", + "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.25.0" + "source": "https://github.com/symfony/finder/tree/5.4" }, "funding": [ { @@ -2329,35 +2544,36 @@ "type": "tidelift" } ], - "time": "2021-02-19T12:13:01+00:00" + "time": "2023-01-14T19:14:44+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.25.0", + "name": "symfony/polyfill-ctype", + "version": "dev-main", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/0abb51d2f102e00a4eefcf46ba7fec406d245825", - "reference": "0abb51d2f102e00a4eefcf46ba7fec406d245825", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/5bbc823adecdae860bb64756d639ecfec17b050a", + "reference": "5bbc823adecdae860bb64756d639ecfec17b050a", "shasum": "" }, "require": { "php": ">=7.1" }, "provide": { - "ext-mbstring": "*" + "ext-ctype": "*" }, "suggest": { - "ext-mbstring": "For best performance" + "ext-ctype": "For best performance" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2369,7 +2585,7 @@ "bootstrap.php" ], "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Ctype\\": "" } }, "notification-url": "https://packagist.org/downloads/", @@ -2378,25 +2594,24 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", + "ctype", "polyfill", - "portable", - "shim" + "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.25.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.27.0" }, "funding": [ { @@ -2412,29 +2627,33 @@ "type": "tidelift" } ], - "time": "2021-11-30T18:21:41+00:00" + "time": "2022-11-03T14:55:06+00:00" }, { - "name": "symfony/polyfill-php73", - "version": "v1.25.0", + "name": "symfony/polyfill-intl-grapheme", + "version": "dev-main", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5" + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/cc5db0e22b3cb4111010e48785a97f670b350ca5", - "reference": "cc5db0e22b3cb4111010e48785a97f670b350ca5", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/511a08c03c1960e08a883f4cffcacd219b758354", + "reference": "511a08c03c1960e08a883f4cffcacd219b758354", "shasum": "" }, "require": { "php": ">=7.1" }, + "suggest": { + "ext-intl": "For best performance" + }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "1.27-dev" }, "thanks": { "name": "symfony/polyfill", @@ -2442,93 +2661,2336 @@ } }, "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Php73\\": "" - }, + "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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "reference": "19bd1e4fcd5b91116f14d8533c57831ed00571b6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "reference": "8ad114f6b39e2c98a8b0e3bd907732c207c2b534", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php73", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php73.git", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "reference": "9e8ecb5f92152187c4799efd3c96b78ccab18ff9", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/polyfill-php81", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php81.git", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/707403074c8ea6e2edaf8794b0157a0bfa52157a", + "reference": "707403074c8ea6e2edaf8794b0157a0bfa52157a", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.27-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.27.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-11-03T14:55:06+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "2.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "reference": "4b426aac47d6427cc1a1d0f7e2ac724627f5966c", + "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/2.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-05-30T19:17:29+00:00" + }, + { + "name": "symfony/string", + "version": "5.4.x-dev", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/0a01071610fd861cc160dfb7e2682ceec66064cb", + "reference": "0a01071610fd861cc160dfb7e2682ceec66064cb", + "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/5.4" + }, + "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": "2023-01-01T08:32:19+00:00" + }, + { + "name": "symfony/translation", + "version": "5.4.x-dev", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695", + "reference": "83d487b13b7fb4c0a6ad079f4e4c9b4525e1b695", + "shasum": "" + }, + "require": { + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16", + "symfony/translation-contracts": "^2.3" + }, + "conflict": { + "symfony/config": "<4.4", + "symfony/console": "<5.3", + "symfony/dependency-injection": "<5.0", + "symfony/http-kernel": "<5.0", + "symfony/twig-bundle": "<5.0", + "symfony/yaml": "<4.4" + }, + "provide": { + "symfony/translation-implementation": "2.3" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^4.4|^5.0|^6.0", + "symfony/console": "^5.4|^6.0", + "symfony/dependency-injection": "^5.0|^6.0", + "symfony/finder": "^4.4|^5.0|^6.0", + "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-kernel": "^5.0|^6.0", + "symfony/intl": "^4.4|^5.0|^6.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/service-contracts": "^1.1.2|^2|^3", + "symfony/yaml": "^4.4|^5.0|^6.0" + }, + "suggest": { + "psr/log-implementation": "To use logging capability in translator", + "symfony/config": "", + "symfony/yaml": "" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "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 to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/5.4" + }, + "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": "2023-01-01T08:32:19+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "2.5.x-dev", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "79cebc7b8c230e88868a3a85693c1e30b44f750e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/79cebc7b8c230e88868a3a85693c1e30b44f750e", + "reference": "79cebc7b8c230e88868a3a85693c1e30b44f750e", + "shasum": "" + }, + "require": { + "php": ">=7.2.5" + }, + "suggest": { + "symfony/translation-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\\Translation\\": "" + } + }, + "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 translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/2.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-10-27T07:55:40+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "1.6.1", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/87337c91b9dfacee02452244ee14ab3c43bc485a", + "reference": "87337c91b9dfacee02452244ee14ab3c43bc485a", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "http://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/1.6.1" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2022-01-24T18:55:24+00:00" + } + ], + "packages-dev": [ + { + "name": "amphp/amp", + "version": "2.x-dev", + "source": { + "type": "git", + "url": "https://github.com/amphp/amp.git", + "reference": "c5ea79065f98f93f7b16a4d5a504fe5d69451447" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/amp/zipball/c5ea79065f98f93f7b16a4d5a504fe5d69451447", + "reference": "c5ea79065f98f93f7b16a4d5a504fe5d69451447", + "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/master" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-08-21T11:55:21+00:00" + }, + { + "name": "amphp/byte-stream", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/amphp/byte-stream.git", + "reference": "18f86b65129d923e004df27e2a3d6f4159c3c743" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/amphp/byte-stream/zipball/18f86b65129d923e004df27e2a3d6f4159c3c743", + "reference": "18f86b65129d923e004df27e2a3d6f4159c3c743", + "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": "https://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/master" + }, + "funding": [ + { + "url": "https://github.com/amphp", + "type": "github" + } + ], + "time": "2022-06-21T18:19:50+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" + }, + "abandoned": "nextcloud/ocp", + "time": "2021-11-11T14:01:42+00:00" + }, + { + "name": "composer/package-versions-deprecated", + "version": "dev-master", + "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" + }, + "default-branch": true, + "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": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "reference": "4bff79ddd77851fe3cdd11616ed3f92841ba5bd2", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.3", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^5" + }, + "default-branch": true, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.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/3.1.0" + }, + "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-11-17T09:50:14+00:00" + }, + { + "name": "composer/semver", + "version": "dev-main", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", + "reference": "fa1ec24f0ab1efe642671ec15c51a3ab879f59bf", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "symfony/phpunit-bridge": "^4.2 || ^5" + }, + "default-branch": true, + "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": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/main" + }, + "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": "2023-01-13T15:47:53+00:00" + }, + { + "name": "composer/xdebug-handler", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/composer/xdebug-handler.git", + "reference": "ced299686f41dce890debac69273b47ffe98a40c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/ced299686f41dce890debac69273b47ffe98a40c", + "reference": "ced299686f41dce890debac69273b47ffe98a40c", + "shasum": "" + }, + "require": { + "composer/pcre": "^1 || ^2 || ^3", + "php": "^7.2.5 || ^8.0", + "psr/log": "^1 || ^2 || ^3" + }, + "require-dev": { + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "symfony/phpunit-bridge": "^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/3.0.3" + }, + "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-25T21:32:43+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.14.x-dev", + "source": { + "type": "git", + "url": "https://github.com/doctrine/annotations.git", + "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/ad785217c1e9555a7d6c6c8c9f406395a5e2882b", + "reference": "ad785217c1e9555a7d6c6c8c9f406395a5e2882b", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^1 || ^2", + "ext-tokenizer": "*", + "php": "^7.1 || ^8.0", + "psr/cache": "^1 || ^2 || ^3" + }, + "require-dev": { + "doctrine/cache": "^1.11 || ^2.0", + "doctrine/coding-standard": "^9 || ^10", + "phpstan/phpstan": "~1.4.10 || ^1.8.0", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "symfony/cache": "^4.4 || ^5.4 || ^6", + "vimeo/psalm": "^4.10" + }, + "suggest": { + "php": "PHP 8.0 or higher comes with attributes, a native replacement for annotations" + }, + "default-branch": true, + "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.14.2" + }, + "time": "2022-12-15T06:48:22+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": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/felixfbecker/php-language-server-protocol.git", + "reference": "ae4c490773bb0d21ca6f5e08a737506f44e175ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/ae4c490773bb0d21ca6f5e08a737506f44e175ea", + "reference": "ae4c490773bb0d21ca6f5e08a737506f44e175ea", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpstan/phpstan": "*", + "squizlabs/php_codesniffer": "^3.1", + "vimeo/psalm": "^4.0" + }, + "default-branch": true, + "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/master" + }, + "time": "2022-06-19T17:15:06+00:00" + }, + { + "name": "friendsofphp/php-cs-fixer", + "version": "v3.13.2", + "source": { + "type": "git", + "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", + "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/3952f08a81bd3b1b15e11c3de0b6bf037faa8496", + "reference": "3952f08a81bd3b1b15e11c3de0b6bf037faa8496", + "shasum": "" + }, + "require": { + "composer/semver": "^3.2", + "composer/xdebug-handler": "^3.0.3", + "doctrine/annotations": "^1.13", + "ext-json": "*", + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0", + "sebastian/diff": "^4.0", + "symfony/console": "^5.4 || ^6.0", + "symfony/event-dispatcher": "^5.4 || ^6.0", + "symfony/filesystem": "^5.4 || ^6.0", + "symfony/finder": "^5.4 || ^6.0", + "symfony/options-resolver": "^5.4 || ^6.0", + "symfony/polyfill-mbstring": "^1.23", + "symfony/polyfill-php80": "^1.25", + "symfony/polyfill-php81": "^1.25", + "symfony/process": "^5.4 || ^6.0", + "symfony/stopwatch": "^5.4 || ^6.0" + }, + "require-dev": { + "justinrainbow/json-schema": "^5.2", + "keradus/cli-executor": "^2.0", + "mikey179/vfsstream": "^1.6.10", + "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": "^2.0", + "phpunit/phpunit": "^9.5", + "phpunitgoodpractices/polyfill": "^1.6", + "phpunitgoodpractices/traits": "^1.9.2", + "symfony/phpunit-bridge": "^6.0", + "symfony/yaml": "^5.4 || ^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/PHP-CS-Fixer/PHP-CS-Fixer/issues", + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.13.2" + }, + "funding": [ + { + "url": "https://github.com/keradus", + "type": "github" + } + ], + "time": "2023-01-02T23:53:50+00:00" + }, + { + "name": "netresearch/jsonmapper", + "version": "v4.1.0", + "source": { + "type": "git", + "url": "https://github.com/cweiske/jsonmapper.git", + "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "reference": "cfa81ea1d35294d64adb9c68aa4cb9e92400e53f", + "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.1.0" + }, + "time": "2022-12-08T20:46:14+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": "4.x-dev", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "reference": "570e980a201d8ed0236b0a62ddf2c9cbb2034039", + "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" + }, + "default-branch": true, + "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.15.3" + }, + "time": "2023-01-16T22:05:37+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": "phpdocumentor/reflection-common", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "a0eeab580cbdf4414fef6978732510a36ed0a9d6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/a0eeab580cbdf4414fef6978732510a36ed0a9d6", + "reference": "a0eeab580cbdf4414fef6978732510a36ed0a9d6", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "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/master" + }, + "time": "2021-06-25T13:47:51+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "566af9fb94c556de91562fcfcbc392f66680111b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/566af9fb94c556de91562fcfcbc392f66680111b", + "reference": "566af9fb94c556de91562fcfcbc392f66680111b", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "1.x-dev@dev", + "phpstan/phpdoc-parser": "^1.7", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.5", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-mockery": "^1.1", + "phpstan/phpstan-webmozart-assert": "^1.2", + "phpunit/phpunit": "^9.5", + "vimeo/psalm": "^4.26" + }, + "default-branch": true, + "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/master" + }, + "time": "2022-11-19T20:28:46+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.x-dev", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "06f36c92b434ac686de06b6563e88046943bccbe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/06f36c92b434ac686de06b6563e88046943bccbe", + "reference": "06f36c92b434ac686de06b6563e88046943bccbe", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpdocumentor/reflection-common": "^2.0", + "phpstan/phpdoc-parser": "^1.13" + }, + "require-dev": { + "ext-tokenizer": "*", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.1", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpunit/phpunit": "^9.5", + "rector/rector": "^0.13.9", + "vimeo/psalm": "^4.25" + }, + "default-branch": true, + "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.x" + }, + "time": "2022-12-16T10:25:14+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.15.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "61800f71a5526081d1b5633766aa88341f1ade76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/61800f71a5526081d1b5633766aa88341f1ade76", + "reference": "61800f71a5526081d1b5633766aa88341f1ade76", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", + "support": { + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.15.3" + }, + "time": "2022-12-20T20:56:55+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/event-dispatcher", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "e275e2d67d53964a3f13e056886ecd769edee021" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/e275e2d67d53964a3f13e056886ecd769edee021", + "reference": "e275e2d67d53964a3f13e056886ecd769edee021", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "suggest": { + "fig/event-dispatcher-util": "Provides some useful PSR-14 utilities" + }, + "default-branch": true, + "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": "https://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "source": "https://github.com/php-fig/event-dispatcher/tree/master" + }, + "time": "2022-06-29T17:22:39+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": [ - "Resources/stubs" + "src/" ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" }, { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], - "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "homepage": "https://symfony.com", + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "diff", + "udiff", + "unidiff", + "unified diff" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.25.0" + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" }, "funding": [ { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", + "url": "https://github.com/sebastianbergmann", "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" } ], - "time": "2021-06-05T21:20:04+00:00" + "time": "2020-10-26T13:10:38+00:00" }, { - "name": "symfony/polyfill-php80", - "version": "v1.25.0", + "name": "symfony/event-dispatcher", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c" + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/4407588e0d3f1f52efb65fbe92babe41f37fe50c", - "reference": "4407588e0d3f1f52efb65fbe92babe41f37fe50c", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/abf49cc084c087d94b4cb939c3f3672971784e0c", + "reference": "abf49cc084c087d94b4cb939c3f3672971784e0c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/polyfill-php80": "^1.16" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } + "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": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php80\\": "" + "Symfony\\Component\\EventDispatcher\\": "" }, - "classmap": [ - "Resources/stubs" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -2537,28 +4999,18 @@ ], "authors": [ { - "name": "Ion Bazan", - "email": "ion.bazan@gmail.com" - }, - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" - ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.25.0" + "source": "https://github.com/symfony/event-dispatcher/tree/5.4" }, "funding": [ { @@ -2574,45 +5026,43 @@ "type": "tidelift" } ], - "time": "2022-03-04T08:16:47+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { - "name": "symfony/polyfill-php81", - "version": "v1.25.0", + "name": "symfony/event-dispatcher-contracts", + "version": "2.5.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f" + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", - "reference": "5de4ba2d41b15f9bd0e19b2ab9674135813ec98f", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", + "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2.5", + "psr/event-dispatcher": "^1" + }, + "suggest": { + "symfony/event-dispatcher-implementation": "" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.23-dev" + "dev-main": "2.5-dev" }, "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" } }, "autoload": { - "files": [ - "bootstrap.php" - ], "psr-4": { - "Symfony\\Polyfill\\Php81\\": "" - }, - "classmap": [ - "Resources/stubs" - ] + "Symfony\\Contracts\\EventDispatcher\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2628,16 +5078,18 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions", + "description": "Generic abstractions related to dispatching event", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "polyfill", - "portable", - "shim" + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.25.0" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/2.5" }, "funding": [ { @@ -2653,30 +5105,32 @@ "type": "tidelift" } ], - "time": "2021-09-13T13:58:11+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { - "name": "symfony/process", - "version": "v5.4.8", + "name": "symfony/filesystem", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3" + "url": "https://github.com/symfony/filesystem.git", + "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", - "reference": "597f3fff8e3e91836bb0bd38f5718b56ddbde2f3", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/648bfaca6a494f3e22378123bcee2894045dc9d8", + "reference": "648bfaca6a494f3e22378123bcee2894045dc9d8", "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\\Process\\": "" + "Symfony\\Component\\Filesystem\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -2696,10 +5150,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Executes commands in sub-processes", + "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v5.4.8" + "source": "https://github.com/symfony/filesystem/tree/5.4" }, "funding": [ { @@ -2715,47 +5169,36 @@ "type": "tidelift" } ], - "time": "2022-04-08T05:07:18+00:00" + "time": "2023-01-14T19:14:44+00:00" }, { - "name": "symfony/service-contracts", - "version": "v2.5.1", + "name": "symfony/options-resolver", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c" + "url": "https://github.com/symfony/options-resolver.git", + "reference": "b03c99236445492f20c61666e8f7e5d388b078e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/24d9dc654b83e91aa59f9d167b131bc3b5bea24c", - "reference": "24d9dc654b83e91aa59f9d167b131bc3b5bea24c", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/b03c99236445492f20c61666e8f7e5d388b078e5", + "reference": "b03c99236445492f20c61666e8f7e5d388b078e5", "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": "" + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php73": "~1.0", + "symfony/polyfill-php80": "^1.16" }, "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\\": "" - } + "Symfony\\Component\\OptionsResolver\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -2763,26 +5206,23 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" } ], - "description": "Generic abstractions related to writing services", + "description": "Provides an improved replacement for the array_replace PHP function", "homepage": "https://symfony.com", "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" + "config", + "configuration", + "options" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v2.5.1" + "source": "https://github.com/symfony/options-resolver/tree/5.4" }, "funding": [ { @@ -2798,30 +5238,30 @@ "type": "tidelift" } ], - "time": "2022-03-13T20:07:29+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { - "name": "symfony/stopwatch", - "version": "v5.4.5", + "name": "symfony/process", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/stopwatch.git", - "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30" + "url": "https://github.com/symfony/process.git", + "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", - "reference": "4d04b5c24f3c9a1a168a131f6cbe297155bc0d30", + "url": "https://api.github.com/repos/symfony/process/zipball/c5ba874c9b636dbccf761e22ce750e88ec3f55e1", + "reference": "c5ba874c9b636dbccf761e22ce750e88ec3f55e1", "shasum": "" }, "require": { "php": ">=7.2.5", - "symfony/service-contracts": "^1|^2|^3" + "symfony/polyfill-php80": "^1.16" }, "type": "library", "autoload": { "psr-4": { - "Symfony\\Component\\Stopwatch\\": "" + "Symfony\\Component\\Process\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -2841,10 +5281,10 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Provides a way to profile code", + "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v5.4.5" + "source": "https://github.com/symfony/process/tree/5.4" }, "funding": [ { @@ -2860,46 +5300,30 @@ "type": "tidelift" } ], - "time": "2022-02-18T16:06:09+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { - "name": "symfony/string", - "version": "v5.4.8", + "name": "symfony/stopwatch", + "version": "5.4.x-dev", "source": { "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8" + "url": "https://github.com/symfony/stopwatch.git", + "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8", - "reference": "3c061a76bff6d6ea427d85e12ad1bb8ed8cd43e8", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/bd2b066090fd6a67039371098fa25a84cb2679ec", + "reference": "bd2b066090fd6a67039371098fa25a84cb2679ec", "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" + "symfony/service-contracts": "^1|^2|^3" }, "type": "library", "autoload": { - "files": [ - "Resources/functions.php" - ], "psr-4": { - "Symfony\\Component\\String\\": "" + "Symfony\\Component\\Stopwatch\\": "" }, "exclude-from-classmap": [ "/Tests/" @@ -2911,26 +5335,18 @@ ], "authors": [ { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" + "name": "Fabien Potencier", + "email": "fabien@symfony.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", + "description": "Provides a way to profile code", "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.8" + "source": "https://github.com/symfony/stopwatch/tree/5.4" }, "funding": [ { @@ -2946,20 +5362,20 @@ "type": "tidelift" } ], - "time": "2022-04-19T10:40:37+00:00" + "time": "2023-01-01T08:32:19+00:00" }, { "name": "vimeo/psalm", - "version": "4.23.0", + "version": "4.x-dev", "source": { "type": "git", "url": "https://github.com/vimeo/psalm.git", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88" + "reference": "f630a0dc399170e5c7e8bd57ee28c2f5d01505e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/f1fe6ff483bf325c803df9f510d09a03fd796f88", - "reference": "f1fe6ff483bf325c803df9f510d09a03fd796f88", + "url": "https://api.github.com/repos/vimeo/psalm/zipball/f630a0dc399170e5c7e8bd57ee28c2f5d01505e6", + "reference": "f630a0dc399170e5c7e8bd57ee28c2f5d01505e6", "shasum": "" }, "require": { @@ -2998,6 +5414,7 @@ "phpdocumentor/reflection-docblock": "^5", "phpmyadmin/sql-parser": "5.1.0||dev-master", "phpspec/prophecy": ">=1.9.0", + "phpstan/phpdoc-parser": "1.2.* || 1.6.4", "phpunit/phpunit": "^9.0", "psalm/plugin-phpunit": "^0.16", "slevomat/coding-standard": "^7.0", @@ -3009,6 +5426,7 @@ "ext-curl": "In order to send data to shepherd", "ext-igbinary": "^2.0.5 is required, used to serialize caching data" }, + "default-branch": true, "bin": [ "psalm", "psalm-language-server", @@ -3051,27 +5469,27 @@ ], "support": { "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm/tree/4.23.0" + "source": "https://github.com/vimeo/psalm/tree/4.x" }, - "time": "2022-04-28T17:35:49+00:00" + "time": "2022-11-07T12:23:42+00:00" }, { "name": "webmozart/assert", - "version": "1.10.0", + "version": "1.11.0", "source": { "type": "git", "url": "https://github.com/webmozarts/assert.git", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", - "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", "shasum": "" }, "require": { - "php": "^7.2 || ^8.0", - "symfony/polyfill-ctype": "^1.8" + "ext-ctype": "*", + "php": "^7.2 || ^8.0" }, "conflict": { "phpstan/phpstan": "<0.12.20", @@ -3109,32 +5527,33 @@ ], "support": { "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.10.0" + "source": "https://github.com/webmozarts/assert/tree/1.11.0" }, - "time": "2021-03-09T10:59:23+00:00" + "time": "2022-06-03T18:03:27+00:00" }, { "name": "webmozart/path-util", - "version": "2.3.0", + "version": "dev-master", "source": { "type": "git", "url": "https://github.com/webmozart/path-util.git", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725" + "reference": "6099b5238073f87f246863fd58c2e447acfc0d24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/path-util/zipball/d939f7edc24c9a1bb9c0dee5cb05d8e859490725", - "reference": "d939f7edc24c9a1bb9c0dee5cb05d8e859490725", + "url": "https://api.github.com/repos/webmozart/path-util/zipball/6099b5238073f87f246863fd58c2e447acfc0d24", + "reference": "6099b5238073f87f246863fd58c2e447acfc0d24", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": "^5.3.3|^7.0", "webmozart/assert": "~1.0" }, "require-dev": { "phpunit/phpunit": "^4.6", "sebastian/version": "^1.0.1" }, + "default-branch": true, "type": "library", "extra": { "branch-alias": { @@ -3159,15 +5578,17 @@ "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" + "source": "https://github.com/webmozart/path-util/tree/master" }, "abandoned": "symfony/filesystem", - "time": "2015-12-17T08:42:14+00:00" + "time": "2021-11-08T08:17:20+00:00" } ], "aliases": [], - "minimum-stability": "stable", - "stability-flags": [], + "minimum-stability": "dev", + "stability-flags": { + "audriga/scim-server-php": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": [], diff --git a/lib/Adapter/Groups/NextcloudGroupAdapter.php b/lib/Adapter/Groups/NextcloudGroupAdapter.php new file mode 100644 index 0000000000000000000000000000000000000000..32f49873f4d9953ffab91a6049b61ca595d87b1c --- /dev/null +++ b/lib/Adapter/Groups/NextcloudGroupAdapter.php @@ -0,0 +1,110 @@ +logger = $container->get(LoggerInterface::class); + $this->userManager = $container->get(IUserManager::class); + $this->request = $container->get(IRequest::class); + } + + /** + * Transform an NC group into a SCIM group + */ + public function getCoreGroup(?IGroup $ncGroup): ?CoreGroup + { + $this->logger->info( + "[" . NextcloudGroupAdapter::class . "] entering getCoreGroup() method" + ); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . "/index.php/apps/scimserviceprovider"; + + if (!isset($ncGroup)) { + $this->logger->error( + "[" . NextcloudGroupAdapter::class . "] passed NC group in getCoreGroup() method is null" + ); + + return null; + } + + $coreGroup = new CoreGroup(); + $coreGroup->setId($ncGroup->getGID()); + $coreGroup->setDisplayName($ncGroup->getDisplayName()); + + $ncGroupMembers = $ncGroup->getUsers(); + + if (isset($ncGroupMembers) && !empty($ncGroupMembers)) { + $coreGroupMembers = []; + + foreach ($ncGroupMembers as $ncGroupMember) { + $coreGroupMember = new MultiValuedAttribute(); + $coreGroupMember->setValue($ncGroupMember->getUID()); + $coreGroupMember->setRef($baseUrl . "/Users/" . $ncGroupMember->getUID()); + $coreGroupMember->setDisplay($ncGroupMember->getDisplayName()); + + $coreGroupMembers[] = $coreGroupMember; + } + + $coreGroup->setMembers($coreGroupMembers); + } + + return $coreGroup; + } + + /** + * Transform a SCIM group into an NC group + * + * Note: the second parameter is needed, since we can't instantiate an NC group + * ourselves and need to receive an instance, passed from somewhere + */ + public function getNCGroup(?CoreGroup $coreGroup, IGroup $ncGroup): ?IGroup + { + $this->logger->info( + "[" . NextcloudGroupAdapter::class . "] entering getNCGroup() method" + ); + + if (!isset($coreGroup) || !isset($ncGroup)) { + $this->logger->error( + "[" . NextcloudGroupAdapter::class . "] passed Core Group in getNCGroup() method is null" + ); + + return null; + } + + $ncGroup->setDisplayName($coreGroup->getDisplayName()); + + if ($coreGroup->getMembers() !== null && !empty($coreGroup->getMembers())) { + foreach ($coreGroup->getMembers() as $coreGroupMember) { + // If user with this uid exists, then add it as a member of the group + if ($coreGroupMember->getValue() !== null && !empty($coreGroupMember->getValue())) { + if ($this->userManager->userExists($coreGroupMember->getValue())) { + $ncGroup->addUser($this->userManager->get($coreGroupMember->getValue())); + } + } + } + } + + return $ncGroup; + } +} diff --git a/lib/Adapter/Users/NextcloudUserAdapter.php b/lib/Adapter/Users/NextcloudUserAdapter.php new file mode 100644 index 0000000000000000000000000000000000000000..5cadcfe671e522b85fd82f01ac1ef06a17457233 --- /dev/null +++ b/lib/Adapter/Users/NextcloudUserAdapter.php @@ -0,0 +1,124 @@ +logger = $container->get(LoggerInterface::class); + $this->config = $container->get(IConfig::class); + $this->userManager = $container->get(IUserManager::class); + $this->secureRandom = $container->get(ISecureRandom::class); + } + + /** + * Transform an NC User into a SCIM user + */ + public function getCoreUser(?IUser $ncUser): ?CoreUser + { + $this->logger->info( + "[" . NextcloudUserAdapter::class . "] entering getCoreUser() method" + ); + + if (!isset($ncUser)) { + $this->logger->error( + "[" . NextcloudUserAdapter::class . "] passed NC user in getCoreUser() method is null" + ); + + return null; + } + + $coreUser = new CoreUser(); + $coreUser->setId($ncUser->getUID()); + + $coreUserName = new Name(); + $coreUserName->setFormatted($ncUser->getDisplayName()); + $coreUser->setName($coreUserName); + + $coreUser->setUserName($ncUser->getUID()); + $coreUser->setDisplayName($ncUser->getDisplayName()); + $coreUser->setActive($ncUser->isEnabled()); + + $ncUserExternalId = $this->config->getUserValue($ncUser->getUID(), 'SCIMServiceProvider', 'ExternalId', ''); + $coreUser->setExternalId($ncUserExternalId); + + if ($ncUser->getEMailAddress() !== null && !empty($ncUser->getEMailAddress())) { + $coreUserEmail = new MultiValuedAttribute(); + $coreUserEmail->setValue($ncUser->getEMailAddress()); + $coreUserEmail->setPrimary(true); + + $coreUser->setEmails(array($coreUserEmail)); + } + + return $coreUser; + } + + /** + * Transform a SCIM user into an NC User + * + * Note: we need the second parameter, since we can't instantiate an NC user in PHP + * ourselves and need to receive an instance that we can populate with data from the SCIM user + */ + public function getNCUser(?CoreUser $coreUser, IUser $ncUser): ?IUser + { + $this->logger->info( + "[" . NextcloudUserAdapter::class . "] entering getNCUser() method" + ); + + if (!isset($coreUser) || !isset($ncUser)) { + $this->logger->error( + "[" . NextcloudUserAdapter::class . "] passed Core User in getNCUser() method is null" + ); + + return null; + } + + if ($coreUser->getDisplayName() !== null && !empty($coreUser->getDisplayName())) { + $ncUser->setDisplayName($coreUser->getDisplayName()); + } + + if ($coreUser->getActive() !== null) { + $ncUser->setEnabled($coreUser->getActive()); + } + + if ($coreUser->getExternalId() !== null && !empty($coreUser->getExternalId())) { + $this->config->setUserValue($ncUser->getUID(), 'SCIMServiceProvider', 'ExternalId', $coreUser->getExternalId()); + } + + if ($coreUser->getEmails() !== null && !empty($coreUser->getEmails())) { + // Here, we use the first email of the SCIM user to set as the NC user's email + // TODO: is this ok or should we rather first iterate and search for a primary email of the SCIM user + if ($coreUser->getEmails()[0] !== null && !empty($coreUser->getEmails()[0])) { + if ($coreUser->getEmails()[0]->getValue() !== null && !empty($coreUser->getEmails()[0]->getValue())) { + $ncUser->setEMailAddress($coreUser->getEmails()[0]->getValue()); + } + } + } + + return $ncUser; + } +} diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php new file mode 100644 index 0000000000000000000000000000000000000000..e176dd841159b82b30c3e8291f2b379972d6d5fa --- /dev/null +++ b/lib/AppInfo/Application.php @@ -0,0 +1,161 @@ +registerService('SCIMUser', function(ContainerInterface $c) { + return new SCIMUser( + $c->get(IUserManager::class), + $c->get(IConfig::class) + ); + }); + + $context->registerService(UserService::class, function(ContainerInterface $c) { + return new UserService($c); + }); + + $context->registerService(GroupService::class, function(ContainerInterface $c) { + return new GroupService($c); + }); + + $context->registerService('UserRepository', function(ContainerInterface $c) { + return new NextcloudUserRepository($c); + }); + + $context->registerService('UserAdapter', function(ContainerInterface $c) { + return new NextcloudUserAdapter($c); + }); + + $context->registerService('UserDataAccess', function(ContainerInterface $c) { + return new NextcloudUserDataAccess($c); + }); + + + $context->registerService('SCIMGroup', function(ContainerInterface $c) { + return new SCIMGroup( + $c->get(IGroupManager::class) + ); + }); + + $context->registerService('GroupRepository', function(ContainerInterface $c) { + return new NextcloudGroupRepository($c); + }); + + $context->registerService('GroupAdapter', function(ContainerInterface $c) { + return new NextcloudGroupAdapter($c); + }); + + $context->registerService('GroupDataAccess', function(ContainerInterface $c) { + return new NextcloudGroupDataAccess($c); + }); + + if (isset($config['auth_type']) && !empty($config['auth_type']) && (strcmp($config['auth_type'], 'bearer') === 0)) { + // If the auth_type is set to "bearer", then use Bearer token endpoints + // For bearer tokens, we also need to register the bearer token auth middleware + $context->registerService(BearerAuthenticator::class, function(ContainerInterface $c) { + return new BearerAuthenticator($c); + }); + + $context->registerService(BearerAuthMiddleware::class, function(ContainerInterface $c) { + return new BearerAuthMiddleware($c); + }); + + $context->registerMiddleware(BearerAuthMiddleware::class); + + $context->registerService(UserBearerController::class, function (ContainerInterface $c) { + return new UserBearerController( + self::APP_ID, + $c->get(IRequest::class), + $c->get(UserService::class) + ); + }); + + $context->registerService(GroupBearerController::class, function (ContainerInterface $c) { + return new GroupBearerController( + self::APP_ID, + $c->get(IRequest::class), + $c->get(GroupService::class) + ); + }); + } else if (!isset($config['auth_type']) || empty($config['auth_type']) || (strcmp($config['auth_type'], 'basic') === 0)) { + // Otherwise, if auth_type is set to "basic" or if it's not set at all, use Basic auth + $context->registerService(UserController::class, function (ContainerInterface $c) { + return new UserController( + self::APP_ID, + $c->get(IRequest::class), + $c->get(UserService::class) + ); + }); + + $context->registerService(GroupController::class, function (ContainerInterface $c) { + return new GroupController( + self::APP_ID, + $c->get(IRequest::class), + $c->get(GroupService::class) + ); + }); + } else { + // In the case of any other auth_type value, complain with an error message + throw new Error("Unknown auth type was set in config file"); + } + } + + /** + * This method is called for starting (i.e., booting) the application + * + * Note: here the method body is empty, since we don't need to do any extra work in it + */ + public function boot(IBootContext $context): void + { + } +} diff --git a/lib/Config/config.php b/lib/Config/config.php new file mode 100644 index 0000000000000000000000000000000000000000..b05857046808e8203fc1c46f875d550c862b8e55 --- /dev/null +++ b/lib/Config/config.php @@ -0,0 +1,14 @@ + 'bearer', + + // Config values for JWTs + 'jwt' => [ + 'secret' => 'secret' + ] +]; diff --git a/lib/Controller/GroupBearerController.php b/lib/Controller/GroupBearerController.php new file mode 100644 index 0000000000000000000000000000000000000000..8a42e66fbb4956884a3bfd6ef1f9e569c7a161b8 --- /dev/null +++ b/lib/Controller/GroupBearerController.php @@ -0,0 +1,99 @@ +groupService = $groupService; + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $filter + * @return SCIMListResponse + * returns a list of groups and their data + */ + public function index(string $filter = ''): SCIMListResponse + { + return $this->groupService->getAll($filter); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * gets group info + * + * @param string $id + * @return SCIMJSONResponse + */ + // TODO: Add filtering support here as well + public function show(string $id): SCIMJSONResponse + { + return $this->groupService->getOneById($id); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $displayName + * @param array $members + * @return SCIMJSONResponse + */ + public function create(string $displayName = '', array $members = []): SCIMJSONResponse + { + return $this->groupService->create($displayName, $members); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $id + * + * @param string $displayName + * @param array $members + * @return SCIMJSONResponse + */ + public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse + { + return $this->groupService->update($id, $displayName, $members); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $id + * @return Response + */ + public function destroy(string $id): Response + { + return $this->groupService->destroy($id); + } +} diff --git a/lib/Controller/GroupController.php b/lib/Controller/GroupController.php index 4715cdc4b1a3823e086150ef31368d26f0a791d7..e9eccde95951e0adfddddcbdb7bb2d1703356b53 100644 --- a/lib/Controller/GroupController.php +++ b/lib/Controller/GroupController.php @@ -6,146 +6,89 @@ namespace OCA\SCIMServiceProvider\Controller; use OCP\AppFramework\ApiController; use OCP\AppFramework\Http\Response; -use OCP\IGroupManager; use OCP\IRequest; -use OCP\IUserManager; -use Psr\Log\LoggerInterface; use OCA\SCIMServiceProvider\Responses\SCIMListResponse; use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; -use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; +use OCA\SCIMServiceProvider\Service\GroupService; -use OCA\SCIMServiceProvider\Service\SCIMGroup; +class GroupController extends ApiController +{ + /** @var GroupService */ + private $groupService; -class GroupController extends ApiController { + public function __construct( + string $appName, + IRequest $request, + GroupService $groupService + ) { + parent::__construct( + $appName, + $request + ); - /** @var LoggerInterface */ - private $logger; - private $SCIMGroup; + $this->groupService = $groupService; + } - public function __construct(string $appName, - IRequest $request, - IUserManager $userManager, - IGroupManager $groupManager, - LoggerInterface $logger, - SCIMGroup $SCIMGroup) { - parent::__construct($appName, - $request, - $userManager, - $groupManager); + /** + * @NoCSRFRequired + * + * @param string $filter + * @return SCIMListResponse + * returns a list of groups and their data + */ + public function index(string $filter = ''): SCIMListResponse + { + return $this->groupService->getAll($filter); + } - $this->logger = $logger; - $this->SCIMGroup = $SCIMGroup; - $this->groupManager = $groupManager; - $this->userManager = $userManager; - } + /** + * @NoCSRFRequired + * + * gets group info + * + * @param string $id + * @return SCIMJSONResponse + */ + // TODO: Add filtering support here as well + public function show(string $id): SCIMJSONResponse + { + return $this->groupService->getOneById($id); + } - /** - * @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->SCIMGroup->get($group->getGID()); - }, $SCIMGroups); - return new SCIMListResponse($SCIMGroups); - } + /** + * @NoCSRFRequired + * + * @param string $displayName + * @param array $members + * @return SCIMJSONResponse + */ + public function create(string $displayName = '', array $members = []): SCIMJSONResponse + { + return $this->groupService->create($displayName, $members); + } - /** - * @NoCSRFRequired - * - * gets group info - * - * @param string $id - * @return SCIMJSONResponse - * @throws Exception - */ - public function show(string $id): SCIMJSONResponse { - $group = $this->SCIMGroup->get($id); - if (empty($group)) { - return new SCIMErrorResponse(['message' => 'Group not found'], 404); - } - return new SCIMJSONResponse($group); - } + /** + * @NoCSRFRequired + * + * @param string $id + * + * @param string $displayName + * @param array $members + * @return SCIMJSONResponse + */ + public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse + { + return $this->groupService->update($id, $displayName, $members); + } - /** - * @NoCSRFRequired - * - * @param string $displayName - * @param array $members - * @return SCIMJSONResponse - * @throws Exception - */ - public function create(string $displayName = '', - array $members = []): SCIMJSONResponse { - $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'], 400); - } - // 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); - } - $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); - } - return new SCIMJSONResponse($this->SCIMGroup->get($id)); - } - - - /** - * @NoCSRFRequired - * - * @param string $id - * - * @param string $displayName - * @param array $members - * @return DataResponse - * @throws Exception - */ - public function update(string $id, - 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); - // todo implement member removal (: - } - return new SCIMJSONResponse($this->SCIMGroup->get($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; - } + /** + * @NoCSRFRequired + * + * @param string $id + * @return Response + */ + public function destroy(string $id): Response + { + return $this->groupService->destroy($id); + } } diff --git a/lib/Controller/ServiceProviderConfigurationController.php b/lib/Controller/ServiceProviderConfigurationController.php new file mode 100644 index 0000000000000000000000000000000000000000..7a9590155da001d3b87a2ad8263a644fb07856c8 --- /dev/null +++ b/lib/Controller/ServiceProviderConfigurationController.php @@ -0,0 +1,61 @@ +logger = $logger; + } + + /** + * @NoCSRFRequired + * @PublicPage + */ + public function resourceTypes(): SCIMListResponse + { + $baseUrl = + $this->request->getServerProtocol() . "://" + . $this->request->getServerHost() . "/" + . Util::SCIM_APP_URL_PATH; + $resourceTypes = SCIMUtil::getResourceTypes($baseUrl); + return new SCIMListResponse($resourceTypes); + } + + /** + * @NoCSRFRequired + * @PublicPage + */ + public function schemas(): SCIMListResponse + { + $schemas = SCIMUtil::getSchemas(); + return new SCIMListResponse($schemas); + } + + /** + * @NoCSRFRequired + * @PublicPage + */ + public function serviceProviderConfig(): SCIMJSONResponse + { + $serviceProviderConfig = SCIMUtil::getServiceProviderConfig(); + return new SCIMJSONResponse($serviceProviderConfig); + } +} diff --git a/lib/Controller/UserBearerController.php b/lib/Controller/UserBearerController.php new file mode 100644 index 0000000000000000000000000000000000000000..bf6ea168f363d908a31be067da7fef62f4111e41 --- /dev/null +++ b/lib/Controller/UserBearerController.php @@ -0,0 +1,121 @@ +userService = $userService; + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $filter + * @return SCIMListResponse + * returns a list of users and their data + */ + public function index(string $filter = ''): SCIMListResponse + { + return $this->userService->getAll($filter); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * gets user info + * + * @param string $id + * @return SCIMJSONResponse + */ + // TODO: Add filtering support here as well + public function show(string $id): SCIMJSONResponse + { + return $this->userService->getOneById($id); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param bool $active + * @param string $displayName + * @param array $emails + * @param string $externalId + * @param string $userName + * @return SCIMJSONResponse + */ + public function create( + bool $active = true, + string $displayName = '', + array $emails = [], + string $externalId = '', + string $userName = '' + ): SCIMJSONResponse + { + return $this->userService->create( + $active, + $displayName, + $emails, + $externalId, + $userName + ); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $id + * + * @param bool $active + * @param string $displayName + * @param array $emails + * @return SCIMJSONResponse + */ + public function update( + string $id, + bool $active, + string $displayName = '', + array $emails = [] + ): SCIMJSONResponse + { + return $this->userService->update($id, $active, $displayName, $emails); + } + + /** + * @NoCSRFRequired + * @PublicPage + * + * @param string $id + * @return Response + */ + public function destroy(string $id): Response + { + return $this->userService->destroy($id); + } +} diff --git a/lib/Controller/UserController.php b/lib/Controller/UserController.php index 2c4c2ca8cb6cce9aae30f8b9330fefc5b09b23bf..6c8236a4b1e79126d8508ef6d83dc5027fb0e50f 100644 --- a/lib/Controller/UserController.php +++ b/lib/Controller/UserController.php @@ -7,172 +7,109 @@ namespace OCA\SCIMServiceProvider\Controller; use OCP\AppFramework\ApiController; use OCP\AppFramework\Http\Response; use OCP\IRequest; -use OCP\IUserManager; -use OCP\Security\ISecureRandom; -use Psr\Log\LoggerInterface; use OCA\SCIMServiceProvider\Responses\SCIMListResponse; use OCA\SCIMServiceProvider\Responses\SCIMJSONResponse; -use OCA\SCIMServiceProvider\Responses\SCIMErrorResponse; - -use OCA\SCIMServiceProvider\Service\SCIMUser; - - -class UserController extends ApiController { - - /** @var LoggerInterface */ - private $logger; - /** @var ISecureRandom */ - private $secureRandom; - private $SCIMUser; - - - public function __construct(string $appName, - IRequest $request, - IUserManager $userManager, - LoggerInterface $logger, - ISecureRandom $secureRandom, - SCIMUser $SCIMUser) { - parent::__construct($appName, - $request, - $userManager); - - $this->logger = $logger; - $this->secureRandom = $secureRandom; - $this->SCIMUser = $SCIMUser; - $this->userManager = $userManager; - } - - /** - * @NoCSRFRequired - * - * returns a list of users and their data - */ - public function index(): SCIMListResponse { - $users = []; - $users = $this->userManager->search('', null, 0); - $userIds = array_keys($users); - - $SCIMUsers = array(); - foreach ($userIds as $userId) { - $userId = (string) $userId; - $SCIMUser = $this->SCIMUser->get($userId); - // Do not insert empty entry - if (!empty($SCIMUser)) { - $SCIMUsers[] = $SCIMUser; - } - } - - return new SCIMListResponse($SCIMUsers); - } - - /** - * @NoCSRFRequired - * - * gets user info - * - * @param string $id - * @return SCIMJSONResponse - * @throws Exception - */ - public function show(string $id): SCIMJSONResponse { - $user = $this->SCIMUser->get($id); - // getUserData returns empty array if not enough permissions - if (empty($user)) { - return new SCIMErrorResponse(['message' => 'User not found'], 404); - } - return new SCIMJSONResponse($user); - } - - /** - * @NoCSRFRequired - * - * @param bool $active - * @param string $displayName - * @param array $emails - * @param string $externalId - * @param string $userName - * @return SCIMJSONResponse - * @throws Exception - */ - public function create(bool $active = true, - string $displayName = '', - array $emails = [], - string $externalId = '', - string $userName = ''): SCIMJSONResponse { - if ($this->userManager->userExists($userName)) { - $this->logger->error('Failed createUser attempt: User already exists.', ['app' => 'SCIMServiceProvider']); - return new SCIMErrorResponse(['message' => 'User already exists'], 409); - } - - try { - $newUser = $this->userManager->createUser($userName, $this->secureRandom->generate(64)); - $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) { - $newUser->setEMailAddress($email['value']); - } - } - $newUser->setEnabled($active); - $this->SCIMUser->setExternalId($userName, $externalId); - return new SCIMJSONResponse($this->SCIMUser->get($userName)); - } catch (Exception $e) { - $this->logger->warning('Failed createUser attempt with SCIMException exeption.', ['app' => 'SCIMServiceProvider']); - throw $e; - } - } - - - /** - * @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->SCIMUser->get($id)); - } - - /** - * @NoCSRFRequired - * - * @param string $id - * @return DataResponse - */ - public function destroy(string $id): Response { - $targetUser = $this->userManager->get($id); - - if ($targetUser === null) { - return new SCIMErrorResponse(['message' => 'User not found'], 404); - } - - // Go ahead with the delete - if ($targetUser->delete()) { - $response = new Response(); - $response->setStatus(204); - return $response; - } else { - return new SCIMErrorResponse(['message' => 'Couldn\'t delete user'], 503); - } - } +use OCA\SCIMServiceProvider\Service\UserService; + +class UserController extends ApiController +{ + /** @var UserService */ + private $userService; + + public function __construct( + string $appName, + IRequest $request, + UserService $userService + ) { + parent::__construct( + $appName, + $request + ); + + $this->userService = $userService; + } + + /** + * @NoCSRFRequired + * + * @param string $filter + * @return SCIMListResponse + * returns a list of users and their data + */ + public function index(string $filter = ''): SCIMListResponse + { + return $this->userService->getAll($filter); + } + + /** + * @NoCSRFRequired + * + * gets user info + * + * @param string $id + * @return SCIMJSONResponse + */ + // TODO: Add filtering support here as well + public function show(string $id): SCIMJSONResponse + { + return $this->userService->getOneById($id); + } + + /** + * @NoCSRFRequired + * + * @param bool $active + * @param string $displayName + * @param array $emails + * @param string $externalId + * @param string $userName + * @return SCIMJSONResponse + */ + public function create( + bool $active = true, + string $displayName = '', + array $emails = [], + string $externalId = '', + string $userName = '' + ): SCIMJSONResponse + { + return $this->userService->create( + $active, + $displayName, + $emails, + $externalId, + $userName + ); + } + + /** + * @NoCSRFRequired + * + * @param string $id + * + * @param bool $active + * @param string $displayName + * @param array $emails + * @return SCIMJSONResponse + */ + public function update( + string $id, + bool $active, + string $displayName = '', + array $emails = [] + ): SCIMJSONResponse + { + return $this->userService->update($id, $active, $displayName, $emails); + } + + /** + * @NoCSRFRequired + * + * @param string $id + * @return Response + */ + public function destroy(string $id): Response + { + return $this->userService->destroy($id); + } } diff --git a/lib/DataAccess/Groups/NextcloudGroupDataAccess.php b/lib/DataAccess/Groups/NextcloudGroupDataAccess.php new file mode 100644 index 0000000000000000000000000000000000000000..e60f87a01276161d49b9b903fc7d9fb22ca2bd45 --- /dev/null +++ b/lib/DataAccess/Groups/NextcloudGroupDataAccess.php @@ -0,0 +1,173 @@ +logger = $container->get(LoggerInterface::class); + $this->userManager = $container->get(IUserManager::class); + $this->groupManager = $container->get(IGroupManager::class); + } + + /** + * Read all groups + */ + public function getAll(): ?array + { + $ncGroups = $this->groupManager->search('', null, 0); + + $this->logger->info( + "[" . NextcloudGroupDataAccess::class . "] fetched " . count($ncGroups) . " groups" + ); + + return $ncGroups; + } + + /** + * Read a single group by ID + */ + public function getOneById($id): ?IGroup + { + $ncGroup = $this->groupManager->get($id); + + if (!isset($ncGroup)) { + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] group with ID: " . $id . " is null" + ); + } else { + $this->logger->info( + "[" . NextcloudGroupDataAccess::class . "] fetched group with ID: " . $id + ); + } + + return $ncGroup; + } + + /** + * Create a new group + */ + public function create($displayName): ?IGroup + { + // Note: the createGroup() function requires a $gid parameter + // However, looking at the NC DB, it seems that the gid of a group + // and its displayName can have the same value, hence here we pass the + // displayName parameter to createGroup() and don't need to generate + // a unique gid for a given group during creation + $createdNcGroup = $this->groupManager->createGroup($displayName); + + if (!isset($createdNcGroup)) { + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] creation of group with displayName: " . $displayName . " failed" + ); + return null; + } + + return $createdNcGroup; + } + + /** + * Update an existing group by ID + * + * Note: here, we pass the second parameter, since it carries the data to be updated + * and we need to pass this data to the group that is to be updated + */ + public function update(string $id, IGroup $newGroupData): ?IGroup + { + $ncGroupToUpdate = $this->groupManager->get($id); + + if (!isset($ncGroupToUpdate)) { + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] group to be updated with ID: " . $id . " doesn't exist" + ); + return null; + } + + if ($newGroupData->getDisplayName() !== null) { + $ncGroupToUpdate->setDisplayName($newGroupData->getDisplayName()); + } + + if ($newGroupData->getUsers() !== null && !empty($newGroupData->getUsers())) { + $newNcGroupMembers = []; + + foreach ($newGroupData->getUsers() as $newNcGroupMember) { + // First check if the user is an existing one and only then try to place it as a member of the group + if ($this->userManager->userExists($newNcGroupMember->getUID())) { + $ncUserToAdd = $this->userManager->get($newNcGroupMember->getUID()); + $newNcGroupMembers[] = $ncUserToAdd; + } else { + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] user from new group data with ID: " . $id . " doesn't exist" + ); + } + } + + $currentNcGroupMembers = $ncGroupToUpdate->getUsers(); + if (isset($currentNcGroupMembers) && !empty($currentNcGroupMembers)) { + // If the group can't remove users from itself, then we abort and return null + if (!$ncGroupToUpdate->canRemoveUser()) { + return null; + } + + // Else, if we can remove users, then we remove all current users + foreach ($currentNcGroupMembers as $currentNcGroupMember) { + $ncGroupToUpdate->removeUser($currentNcGroupMember); + } + } + + // After having deleted the current members, we try to replace them with the new ones + if (!$ncGroupToUpdate->canAddUser()) { + return null; + } + + foreach ($newNcGroupMembers as $newNcGroupMember) { + $ncGroupToUpdate->addUser($newNcGroupMember); + } + } + + // Return the now updated NC group + return $this->groupManager->get($id); + } + + /** + * Delete an existing group by ID + */ + public function delete($id): bool + { + $ncGroupToDelete = $this->groupManager->get($id); + + if (!isset($ncGroupToDelete)) { + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] group to be deleted with ID: " . $id . " doesn't exist" + ); + + return false; + } + + if ($ncGroupToDelete->delete()) { + return true; + } + + $this->logger->error( + "[" . NextcloudGroupDataAccess::class . "] couldn't delete group with ID: " . $id + ); + + return false; + } +} diff --git a/lib/DataAccess/Users/NextcloudUserDataAccess.php b/lib/DataAccess/Users/NextcloudUserDataAccess.php new file mode 100644 index 0000000000000000000000000000000000000000..857919ca8859bdbcb9288ff465a9a757ae0e697b --- /dev/null +++ b/lib/DataAccess/Users/NextcloudUserDataAccess.php @@ -0,0 +1,144 @@ +logger = $container->get(LoggerInterface::class); + $this->secureRandom = $container->get(ISecureRandom::class); + $this->userManager = $container->get(IUserManager::class); + $this->config = $container->get(IConfig::class); + } + + /** + * Read all users + */ + public function getAll(): ?array + { + $ncUsers = $this->userManager->search('', null, 0); + + $this->logger->info( + "[" . NextcloudUserDataAccess::class . "] fetched " . count($ncUsers) . " users" + ); + + return $ncUsers; + } + + /** + * Read a single user by ID + */ + public function getOneById($id): ?IUser + { + $ncUser = $this->userManager->get($id); + + if (!isset($ncUser)) { + $this->logger->error( + "[" . NextcloudUserDataAccess::class . "] user with ID: " . $id . " is null" + ); + } else { + $this->logger->info( + "[" . NextcloudUserDataAccess::class . "] fetched user with ID: " . $id + ); + } + + return $ncUser; + } + + /** + * Create a new user + */ + public function create($username): ?IUser + { + $createdNcUser = $this->userManager->createUser($username, $this->secureRandom->generate(64)); + + if ($createdNcUser === false) { + $this->logger->error( + "[" . NextcloudUserDataAccess::class . "] creation of user with userName: " . $username . " failed" + ); + return null; + } + + return $createdNcUser; + } + + /** + * Update an existing user by ID + * + * Note: here, we pass the second parameter, since it carries the data to be updated + * and we need to pass this data to the user that is to be updated + */ + public function update(string $id, IUser $newUserData): ?IUser + { + $ncUserToUpdate = $this->userManager->get($id); + + if ($ncUserToUpdate === null) { + $this->logger->error( + "[" . NextcloudUserDataAccess::class . "] user to be updated with ID: " . $id . " doesn't exist" + ); + + return null; + } + + if ($newUserData->getDisplayName() !== null) { + $ncUserToUpdate->setDisplayName($newUserData->getDisplayName()); + } + + if ($newUserData->isEnabled() !== null && $newUserData->isEnabled()) { + $ncUserToUpdate->setEnabled($newUserData->isEnabled()); + } + + if ($newUserData->getEMailAddress() !== null && !empty($newUserData->getEMailAddress())) { + $ncUserToUpdate->setEMailAddress($newUserData->getEMailAddress()); + } + + // Return the now updated NC user + return $this->userManager->get($id); + } + + /** + * Delete an existing user by ID + */ + public function delete($id): bool + { + $ncUserToDelete = $this->userManager->get($id); + + if ($ncUserToDelete === null) { + $this->logger->error( + "[" . NextcloudUserDataAccess::class . "] user to be deleted with ID: " . $id . " doesn't exist" + ); + + return false; + } + + if ($ncUserToDelete->delete()) { + return true; + } + + $this->logger->error( + "[" . NextcloudUserDataAccess::class . "] couldn't delete user with ID: " . $id + ); + + return false; + } +} diff --git a/lib/Exception/AuthException.php b/lib/Exception/AuthException.php new file mode 100644 index 0000000000000000000000000000000000000000..ca618fc892b4e6cb91135d17259a481c57297271 --- /dev/null +++ b/lib/Exception/AuthException.php @@ -0,0 +1,9 @@ +request = $container->get(IRequest::class); + $this->bearerAuthenticator = $container->get(BearerAuthenticator::class); + } + + public function beforeController($controller, $methodName) + { + $currentRoute = $this->request->getParams()["_route"]; + $publicRoutes = [ + "scimserviceprovider.service_provider_configuration.resource_types", + "scimserviceprovider.service_provider_configuration.schemas", + "scimserviceprovider.service_provider_configuration.service_provider_config" + ]; + + // Don't require an auth header for public routes + if (in_array($currentRoute, $publicRoutes)) { + return; + } + + $authHeader = $this->request->getHeader('Authorization'); + + if (empty($authHeader)) { + throw new AuthException("No Authorization header supplied"); + } + + $authHeaderSplit = explode(' ', $authHeader); + if (count($authHeaderSplit) !== 2 || strcmp($authHeaderSplit[0], "Bearer") !== 0) { + throw new AuthException("Incorrect Bearer token format"); + } + + $token = $authHeaderSplit[1]; + + // Currently the second parameter to authenticate() is an empty array + // (the second parameter is meant to carry authorization information) + if (!$this->bearerAuthenticator->authenticate($token, [])) { + throw new AuthException("Bearer token is invalid"); + } + } + + public function afterException($controller, $methodName, Exception $exception) + { + if ($exception instanceof AuthException) { + return new SCIMErrorResponse(['message' => $exception->getMessage()], 401); + } + } +} diff --git a/lib/Middleware/ContentTypeMiddleware.php b/lib/Middleware/ContentTypeMiddleware.php new file mode 100644 index 0000000000000000000000000000000000000000..8d8a28f4375b07d0c8a9faa2663b59038eba1bff --- /dev/null +++ b/lib/Middleware/ContentTypeMiddleware.php @@ -0,0 +1,60 @@ +request = $container->get(IRequest::class); + } + + public function beforeController($controller, $methodName) + { + $requestMethod = $this->request->getMethod(); + + // If the incoming request is POST or PUT => check the Content-Type header and the request body + if (in_array(strtolower($requestMethod), array("post", "put"))) { + $contentTypeHeader = $this->request->getHeader("Content-Type"); + if (!isset($contentTypeHeader) || empty($contentTypeHeader)) { + throw new ContentTypeException("Content-Type header not set"); + } + + // Accept both "application/scim+json" and "application/json" as valid headers + // See https://www.rfc-editor.org/rfc/rfc7644.html#section-3.8 + if ( + strpos($contentTypeHeader, "application/scim+json") === false + && strpos($contentTypeHeader, "application/json") === false + ) { + throw new ContentTypeException("Content-Type header is not application/scim+json or application/json"); + } + + // Verify that the request body is indeed valid JSON + $requestBody = $this->request->getParams(); + if (isset($requestBody) && !empty($requestBody)) { + $requestBody = array_keys($requestBody)[0]; + + if (json_decode($requestBody) === false) { + throw new ContentTypeException("Request body is not valid JSON"); + } + } + } + } + + public function afterException($controller, $methodName, Exception $exception) + { + return new SCIMErrorResponse(['message' => $exception->getMessage()], 400); + } +} \ No newline at end of file diff --git a/lib/Repositories/Groups/NextcloudGroupRepository.php b/lib/Repositories/Groups/NextcloudGroupRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..8a938146beac04d00dbaec7f0f7951623bb3cc74 --- /dev/null +++ b/lib/Repositories/Groups/NextcloudGroupRepository.php @@ -0,0 +1,164 @@ +dataAccess = $container->get('GroupDataAccess'); + $this->adapter = $container->get('GroupAdapter'); + $this->logger = $container->get(LoggerInterface::class); + } + + /** + * Read all groups in SCIM format + */ + public function getAll( + $filter = '', + $startIndex = 0, + $count = 0, + $attributes = [], + $excludedAttributes = [] + ): array { + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] reading all groups" + ); + + // Read all NC groups + $ncGroups = $this->dataAccess->getAll(); + $scimGroups = []; + + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] fetched " . count($ncGroups) . " NC groups" + ); + + foreach ($ncGroups as $ncGroup) { + $scimGroup = $this->adapter->getCoreGroup($ncGroup); + $scimGroups[] = $scimGroup; + } + + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] transformed " . count($scimGroups) . " SCIM groups" + ); + + if (isset($filter) && !empty($filter)) { + $scimGroupsToFilter = []; + foreach ($scimGroups as $scimGroup) { + $scimGroupsToFilter[] = $scimGroup->toSCIM(false); + } + + $filteredScimData = FilterUtil::performFiltering($filter, $scimGroupsToFilter); + + $scimGroups = []; + foreach ($filteredScimData as $filteredScimGroup) { + $scimGroup = new CoreGroup(); + $scimGroup->fromSCIM($filteredScimGroup); + $scimGroups[] = $scimGroup; + } + + return $scimGroups; + } + + return $scimGroups; + } + + /** + * Read a single group by ID in SCIM format + */ + public function getOneById( + string $id, + $filter = '', + $startIndex = 0, + $count = 0, + $attributes = [], + $excludedAttributes = [] + ): ?CoreGroup { + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] reading group with ID: " . $id + ); + + $ncGroup = $this->dataAccess->getOneById($id); + return $this->adapter->getCoreGroup($ncGroup); + } + + /** + * Create a group from SCIM data + */ + public function create($object): ?CoreGroup + { + $scimGroupToCreate = new CoreGroup(); + $scimGroupToCreate->fromSCIM($object); + + $displayName = $scimGroupToCreate->getDisplayName(); + $ncGroupCreated = $this->dataAccess->create($displayName); + + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] creating group with displayName: " . $displayName + ); + + if (isset($ncGroupCreated)) { + // Set the rest of the properties of the NC group with the adapter + $ncGroupCreated = $this->adapter->getNCGroup($scimGroupToCreate, $ncGroupCreated); + return $this->adapter->getCoreGroup($ncGroupCreated); + } + + $this->logger->error( + "[" . NextcloudGroupRepository::class . "] creation of group with displayName: " . $displayName . " failed" + ); + + return null; + } + + /** + * Update a group by ID from SCIM data + */ + public function update(string $id, $object): ?CoreGroup + { + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] updating group with ID: " . $id + ); + + $scimGroupToUpdate = new CoreGroup(); + $scimGroupToUpdate->fromSCIM($object); + + $ncGroup = $this->dataAccess->getOneById($id); + + if (isset($ncGroup)) { + $ncGroupToUpdate = $this->adapter->getNCGroup($scimGroupToUpdate, $ncGroup); + $ncGroupUpdated = $this->dataAccess->update($id, $ncGroupToUpdate); + + if (isset($ncGroupUpdated)) { + return $this->adapter->getCoreGroup($ncGroupUpdated); + } + } + + $this->logger->error( + "[" . NextcloudGroupRepository::class . "] update of group with ID: " . $id . " failed" + ); + + return null; + } + + /** + * Delete a group by ID + */ + public function delete(string $id): bool + { + $this->logger->info( + "[" . NextcloudGroupRepository::class . "] deleting group with ID: " . $id + ); + + return $this->dataAccess->delete($id); + } +} diff --git a/lib/Repositories/Users/NextcloudUserRepository.php b/lib/Repositories/Users/NextcloudUserRepository.php new file mode 100644 index 0000000000000000000000000000000000000000..9e3b6a89ef77a7765da8c5a46a4777c2e0e2e15b --- /dev/null +++ b/lib/Repositories/Users/NextcloudUserRepository.php @@ -0,0 +1,177 @@ +dataAccess = $container->get('UserDataAccess'); + $this->adapter = $container->get('UserAdapter'); + $this->logger = $container->get(LoggerInterface::class); + } + + /** + * Read all users in SCIM format + */ + public function getAll( + $filter = '', + $startIndex = 0, + $count = 0, + $attributes = [], + $excludedAttributes = [] + ): array { + $this->logger->info( + "[" . NextcloudUserRepository::class . "] reading all users" + ); + + // Read all NC users + $ncUsers = $this->dataAccess->getAll(); + $scimUsers = []; + + $this->logger->info( + "[" . NextcloudUserRepository::class . "] fetched " . count($ncUsers) . " NC users" + ); + + foreach ($ncUsers as $ncUser) { + $scimUser = $this->adapter->getCoreUser($ncUser); + $scimUsers[] = $scimUser; + } + + $this->logger->info( + "[" . NextcloudUserRepository::class . "] transformed " . count($scimUsers) . " SCIM users" + ); + + if (isset($filter) && !empty($filter)) { + $scimUsersToFilter = []; + foreach ($scimUsers as $scimUser) { + $scimUsersToFilter[] = $scimUser->toSCIM(false); + } + + $filteredScimData = FilterUtil::performFiltering($filter, $scimUsersToFilter); + + $scimUsers = []; + foreach ($filteredScimData as $filteredScimUser) { + $scimUser = new CoreUser(); + $scimUser->fromSCIM($filteredScimUser); + $scimUsers[] = $scimUser; + } + + return $scimUsers; + } + + return $scimUsers; + } + + /** + * Read a single user by ID in SCIM format + */ + public function getOneById( + string $id, + $filter = '', + $startIndex = 0, + $count = 0, + $attributes = [], + $excludedAttributes = [] + ): ?CoreUser { + $this->logger->info( + "[" . NextcloudUserRepository::class . "] reading user with ID: " . $id + ); + + $ncUser = $this->dataAccess->getOneById($id); + $scimUser = $this->adapter->getCoreUser($ncUser); + + if (isset($filter) && !empty($filter)) { + $scimUsersToFilter = array($scimUser->toSCIM(false)); + $filteredScimData = FilterUtil::performFiltering($filter, $scimUsersToFilter); + + if (!empty($filteredScimData)) { + $scimUser = new CoreUser(); + $scimUser->fromSCIM($filteredScimData[0]); + return $scimUser; + } + } + + return $scimUser; + } + + /** + * Create a user from SCIM data + */ + public function create($object): ?CoreUser + { + $scimUserToCreate = new CoreUser(); + $scimUserToCreate->fromSCIM($object); + + $username = $scimUserToCreate->getUserName(); + $ncUserCreated = $this->dataAccess->create($username); + + $this->logger->info( + "[" . NextcloudUserRepository::class . "] creating user with userName: " . $username + ); + + if (isset($ncUserCreated)) { + // Set the rest of the properties of the NC user via the adapter + $ncUserCreated = $this->adapter->getNCUser($scimUserToCreate, $ncUserCreated); + return $this->adapter->getCoreUser($ncUserCreated); + } + + $this->logger->error( + "[" . NextcloudUserRepository::class . "] creation of user with username: " . $username . " failed" + ); + + return null; + } + + /** + * Update a user by ID from SCIM data + */ + public function update(string $id, $object): ?CoreUser + { + $this->logger->info( + "[" . NextcloudUserRepository::class . "] updating user with ID: " . $id + ); + + $scimUserToUpdate = new CoreUser(); + $scimUserToUpdate->fromSCIM($object); + + $ncUser = $this->dataAccess->getOneById($id); + + if (isset($ncUser)) { + $ncUserToUpdate = $this->adapter->getNCUser($scimUserToUpdate, $ncUser); + $ncUserUpdated = $this->dataAccess->update($id, $ncUserToUpdate); + + if (isset($ncUserUpdated)) { + return $this->adapter->getCoreUser($ncUserUpdated); + } + } + + $this->logger->error( + "[" . NextcloudUserRepository::class . "] update of user with ID: " . $id . " failed" + ); + + return null; + } + + /** + * Delete a user by ID + */ + public function delete(string $id): bool + { + $this->logger->info( + "[" . NextcloudUserRepository::class . "] deleting user with ID: " . $id + ); + + return $this->dataAccess->delete($id); + } +} diff --git a/lib/Service/GroupService.php b/lib/Service/GroupService.php new file mode 100644 index 0000000000000000000000000000000000000000..77f439157c480531e89799258b05f7fcb8b37d36 --- /dev/null +++ b/lib/Service/GroupService.php @@ -0,0 +1,157 @@ +logger = $container->get(LoggerInterface::class); + $this->repository = $container->get('GroupRepository'); + $this->groupManager = $container->get(IGroupManager::class); + $this->request = $container->get(IRequest::class); + } + + public function getAll(string $filter = ''): SCIMListResponse + { + $this->logger->info("Reading all groups"); + + $baseUrl = $this->request->getServerProtocol() . "://" + . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $groups = $this->repository->getAll($filter); + + $scimGroups = []; + if (!empty($groups)) { + foreach ($groups as $group) { + $scimGroups[] = $group->toSCIM(false, $baseUrl); + } + } + + return new SCIMListResponse($scimGroups); + } + + public function getOneById(string $id): SCIMJSONResponse + { + $this->logger->info("Reading group with ID: " . $id); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $group = $this->repository->getOneById($id); + if (!isset($group) || empty($group)) { + $this->logger->error("Group with ID " . $id . " not found"); + return new SCIMErrorResponse(['message' => 'Group not found'], 404); + } + return new SCIMJSONResponse($group->toSCIM(false, $baseUrl)); + } + + public function create(string $displayName = '', array $members = []): SCIMJSONResponse + { + $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'], 400); + } + // Check if it exists + if ($this->groupManager->groupExists($id)) { + $this->logger->error("Group to be created already exists"); + return new SCIMErrorResponse(['message' => 'Group exists'], 409); + } + + try { + $this->logger->info("Creating group with displayName: " . $displayName); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $data = [ + 'displayName' => $displayName, + 'members' => $members + ]; + + $createdGroup = $this->repository->create($data); + if (isset($createdGroup) && !empty($createdGroup)) { + return new SCIMJSONResponse($createdGroup->toSCIM(false, $baseUrl), 201); + } else { + $this->logger->error("Creating group failed"); + return new SCIMErrorResponse(['message' => 'Creating group failed'], 400); + } + } catch (Exception $e) { + $this->logger->warning('Failed createGroup attempt with SCIMException exception.', ['app' => 'SCIMServiceProvider']); + throw $e; + } + } + + public function update(string $id, string $displayName = '', array $members = []): SCIMJSONResponse + { + $this->logger->info("Updating group with ID: " . $id); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $group = $this->repository->getOneById($id); + if (!isset($group) || empty($group)) { + $this->logger->error("Group with ID " . $id . " not found for update"); + return new SCIMErrorResponse(['message' => 'Group not found'], 404); + } + + $data = [ + 'displayName' => $displayName, + 'members' => $members + ]; + + $updatedGroup = $this->repository->update($id, $data); + if (isset($updatedGroup) && !empty($updatedGroup)) { + return new SCIMJSONResponse($updatedGroup->toSCIM(false, $baseUrl)); + } else { + $this->logger->error("Updating group with ID " . $id . " failed"); + return new SCIMErrorResponse(['message' => 'Updating group failed'], 400); + } + } + + public function destroy(string $id): Response + { + $this->logger->info("Deleting group with ID: " . $id); + + if ($id === 'admin') { + // Cannot delete admin group + $this->logger->error("Deleting admin group is not allowed"); + return new SCIMErrorResponse(['message' => 'Can\'t delete admin group'], 403); + } + + $deleteRes = $this->repository->delete($id); + + if ($deleteRes) { + $response = new Response(); + $response->setStatus(204); + return $response; + } else { + $this->logger->error("Deletion of group with ID " . $id . " failed"); + return new SCIMErrorResponse(['message' => 'Couldn\'t delete group'], 503); + } + } +} diff --git a/lib/Service/UserService.php b/lib/Service/UserService.php new file mode 100644 index 0000000000000000000000000000000000000000..9973ea716a49bc805afcb51e296b4acb0ef8e0ae --- /dev/null +++ b/lib/Service/UserService.php @@ -0,0 +1,149 @@ +logger = $container->get(LoggerInterface::class); + $this->repository = $container->get('UserRepository'); + $this->request = $container->get(IRequest::class); + } + + public function getAll(string $filter = ''): SCIMListResponse + { + $this->logger->info("Reading all users"); + + $baseUrl = $this->request->getServerProtocol() . "://" + . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $users = $this->repository->getAll($filter); + + $scimUsers = []; + if (!empty($users)) { + foreach ($users as $user) { + $scimUsers[] = $user->toSCIM(false, $baseUrl); + } + } + + return new SCIMListResponse($scimUsers); + } + + public function getOneById(string $id): SCIMJSONResponse + { + $this->logger->info("Reading user with ID: " . $id); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $user = $this->repository->getOneById($id); + if (!isset($user) || empty($user)) { + $this->logger->error("User with ID " . $id . " not found"); + return new SCIMErrorResponse(['message' => 'User not found'], 404); + } + return new SCIMJSONResponse($user->toSCIM(false, $baseUrl)); + } + + public function create( + bool $active = true, + string $displayName = '', + array $emails = [], + string $externalId = '', + string $userName = '' + ): SCIMJSONResponse + { + try { + $this->logger->info("Creating user with userName: " . $userName); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $data = [ + 'active' => $active, + 'displayName' => $displayName, + 'emails' => $emails, + 'externalId' => $externalId, + 'userName' => $userName + ]; + + $createdUser = $this->repository->create($data); + if (isset($createdUser) && !empty($createdUser)) { + return new SCIMJSONResponse($createdUser->toSCIM(false, $baseUrl), 201); + } else { + $this->logger->error("Creating user failed"); + return new SCIMErrorResponse(['message' => 'Creating user failed'], 400); + } + } catch (Exception $e) { + $this->logger->warning('Failed createUser attempt with SCIMException exeption.', ['app' => 'SCIMServiceProvider']); + throw $e; + } + } + + public function update( + string $id, + bool $active, + string $displayName = '', + array $emails = [] + ): SCIMJSONResponse + { + $this->logger->info("Updating user with ID: " . $id); + + $baseUrl = $this->request->getServerProtocol() . "://" . $this->request->getServerHost() . Util::SCIM_APP_URL_PATH; + + $user = $this->repository->getOneById($id); + if (!isset($user) || empty($user)) { + $this->logger->error("User with ID " . $id . " not found for update"); + return new SCIMErrorResponse(['message' => 'User not found'], 404); + } + + $data = [ + 'active' => $active, + 'displayName' => $displayName, + 'emails' => $emails + ]; + + $updatedUser = $this->repository->update($id, $data); + if (isset($updatedUser) && !empty($updatedUser)) { + return new SCIMJSONResponse($updatedUser->toSCIM(false, $baseUrl)); + } else { + $this->logger->error("Updating user with ID " . $id . " failed"); + return new SCIMErrorResponse(['message' => 'Updating user failed'], 400); + } + } + + public function destroy(string $id): Response + { + $this->logger->info("Deleting user with ID: " . $id); + + $deleteRes = $this->repository->delete($id); + + if ($deleteRes) { + $response = new Response(); + $response->setStatus(204); + return $response; + } else { + $this->logger->error("Deletion of user with ID " . $id . " failed"); + return new SCIMErrorResponse(['message' => 'Couldn\'t delete user'], 503); + } + } +} diff --git a/lib/Util/Authentication/BearerAuthenticator.php b/lib/Util/Authentication/BearerAuthenticator.php new file mode 100644 index 0000000000000000000000000000000000000000..08a81a494a3fc3f77c6f78a3636006ff4ae3cc95 --- /dev/null +++ b/lib/Util/Authentication/BearerAuthenticator.php @@ -0,0 +1,56 @@ +logger = $container->get(LoggerInterface::class); + $this->userManager = $container->get(IUserManager::class); + } + + public function authenticate(string $credentials, array $authorizationInfo): bool + { + $jwtPayload = []; + $jwtSecret = Util::getConfigFile()['jwt']['secret']; + try { + $jwtPayload = (array) JWT::decode($credentials, new Key($jwtSecret, 'HS256')); + } catch (Exception $e) { + $this->logger->error($e->getMessage()); + return false; + } + + // If the 'user' claim is missing from the JWT, then auth is considered to have failed + if (!isset($jwtPayload['user']) || empty($jwtPayload['user'])) { + $this->logger->error("No \"user\" claim found in JWT"); + return false; + } + + $username = $jwtPayload['user']; + + // If we managed to find a user with that username, then auth succeeded + $user = $this->userManager->get($username); + if ($user !== null) { + return true; + } + + $this->logger->error("User with this username doesn't exist"); + return false; + } +} diff --git a/lib/Util/Util.php b/lib/Util/Util.php new file mode 100644 index 0000000000000000000000000000000000000000..7f869b844d594422aaf7779791c50febf6900ce4 --- /dev/null +++ b/lib/Util/Util.php @@ -0,0 +1,16 @@ + {", + " pm.response.to.have.status(201);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"createdtestgroup\");", + "});", + "", + "pm.test(\"Response body contains a valid non-null group ID (the ID of the group which was created)\", () => {", + " pm.expect(pm.response.json().id).to.not.be.null;", + "});", + "", + "pm.collectionVariables.set(\"testGroupId\", pm.response.json().id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"createdtestgroup\",\n \"members\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/Groups", + "host": [ + "{{url}}" + ], + "path": [ + "Groups" + ] + } + }, + "response": [] + }, + { + "name": "Read a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the group ID of the group we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testGroupId'));", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"createdtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + }, + { + "name": "Read all groups", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " var resources = pm.response.json().Resources.map(x => x.displayName);", + " pm.expect(resources).to.contain(\"createdtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/Groups", + "host": [ + "{{url}}" + ], + "path": [ + "Groups" + ] + } + }, + "response": [] + }, + { + "name": "Update a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the group ID of the group we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testGroupId'));", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"updatedtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"updatedtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"updatedtestgroup\",\n \"members\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + }, + { + "name": "Delete a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 204\", () => {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{url}}/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "admin", + "type": "string" + }, + { + "key": "username", + "value": "admin", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "ResourceTypes", + "item": [ + { + "name": "Read all ResourceTypes", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains exactly one entry\", () => {", + " pm.expect(pm.response.json().Resources.length).to.eql(2);", + "});", + "", + "pm.test(\"Response body contains ResourceType with id \\\"User\\\"\", () => {", + " pm.expect(pm.response.json().Resources[0].id).to.eql(\"User\");", + "});", + "", + "pm.test(\"Response body contains ResourceType with id \\\"Group\\\"\", () => {", + " pm.expect(pm.response.json().Resources[1].id).to.eql(\"Group\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer: {{jwt_token}}", + "type": "default" + } + ], + "url": { + "raw": "{{url}}/ResourceTypes", + "host": [ + "{{url}}" + ], + "path": [ + "ResourceTypes" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Schemas", + "item": [ + { + "name": "Read all Schemas", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains exactly four entries\", () => {", + " pm.expect(pm.response.json().Resources.length).to.eql(4);", + "});", + "", + "pm.test(\"Response body contains Schema with id \\\"urn:ietf:params:scim:schemas:core:2.0:Group\\\"\", () => {", + " pm.expect(pm.response.json().Resources[0].id).to.eql(\"urn:ietf:params:scim:schemas:core:2.0:Group\");", + "});", + "", + "pm.test(\"Response body contains Schema with id \\\"urn:ietf:params:scim:schemas:core:2.0:ResourceType\\\"\", () => {", + " pm.expect(pm.response.json().Resources[1].id).to.eql(\"urn:ietf:params:scim:schemas:core:2.0:ResourceType\");", + "});", + "", + "pm.test(\"Response body contains Schema with id \\\"urn:ietf:params:scim:schemas:core:2.0:User\\\"\", () => {", + " pm.expect(pm.response.json().Resources[2].id).to.eql(\"urn:ietf:params:scim:schemas:core:2.0:User\");", + "});", + "", + "pm.test(\"Response body contains Schema with id \\\"urn:ietf:params:scim:schemas:core:2.0:Schema\\\"\", () => {", + " pm.expect(pm.response.json().Resources[3].id).to.eql(\"urn:ietf:params:scim:schemas:core:2.0:Schema\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer: {{jwt_token}}", + "type": "default" + } + ], + "url": { + "raw": "{{url}}/Schemas", + "host": [ + "{{url}}" + ], + "path": [ + "Schemas" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "ServiceProviderConfigs", + "item": [ + { + "name": "Read all ServiceProviderConfigs", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains a ServiceProviderConfig with a correct schema\", () => {", + " pm.expect(pm.response.json().schemas).to.include(\"urn:ietf:params:scim:schemas:core:2.0:ServiceProviderConfig\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [ + { + "key": "Authorization", + "value": "Bearer: {{jwt_token}}", + "type": "default" + } + ], + "url": { + "raw": "{{url}}/ServiceProviderConfig", + "host": [ + "{{url}}" + ], + "path": [ + "ServiceProviderConfig" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Users", + "item": [ + { + "name": "Create a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 201\", () => {", + " pm.response.to.have.status(201);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " pm.expect(pm.response.json().userName).to.eql(\"createdtestuser\");", + "});", + "", + "pm.test(\"Response body contains a valid non-null user ID (the ID of the user which was created)\", () => {", + " pm.expect(pm.response.json().id).to.not.be.null;", + "});", + "", + "pm.collectionVariables.set(\"testUserId\", pm.response.json().id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"userName\": \"createdtestuser\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/Users", + "host": [ + "{{url}}" + ], + "path": [ + "Users" + ] + } + }, + "response": [] + }, + { + "name": "Read a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the user ID of the user we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testUserId'));", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " pm.expect(pm.response.json().userName).to.eql(\"createdtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + }, + { + "name": "Read all users", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " var resources = pm.response.json().Resources.map(x => x.userName);", + " pm.expect(resources).to.contain(\"createdtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/Users", + "host": [ + "{{url}}" + ], + "path": [ + "Users" + ] + } + }, + "response": [] + }, + { + "name": "Update a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the user ID of the user we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testUserId'));", + "});", + "", + "pm.test(\"Response body contains user with displayName \\\"updatedtestuser\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"updatedtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"updatedtestuser\",\n \"active\": false\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + }, + { + "name": "Delete a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 204\", () => {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"userName\": \"updatedtestuser\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "admin", + "type": "string" + }, + { + "key": "username", + "value": "admin", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "auth": { + "type": "basic", + "basic": [ + { + "key": "password", + "value": "admin", + "type": "string" + }, + { + "key": "username", + "value": "admin", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "testUserId", + "value": "" + }, + { + "key": "testGroupId", + "value": "" + }, + { + "key": "url", + "value": "http://localhost:8888/index.php/apps/scimserviceprovider", + "type": "default" + } + ] +} \ No newline at end of file diff --git a/tests/postman/bearer_token_api_tests.postman_collection.json b/tests/postman/bearer_token_api_tests.postman_collection.json new file mode 100644 index 0000000000000000000000000000000000000000..36e6104f1a5f033c6dc55e20dc168d9f6674c3d4 --- /dev/null +++ b/tests/postman/bearer_token_api_tests.postman_collection.json @@ -0,0 +1,583 @@ +{ + "info": { + "_postman_id": "606af599-3dec-46c8-9464-f52a7fd8f5b7", + "name": "SCIM Nextcloud App Collection (Bearer Token)", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Users", + "item": [ + { + "name": "Create a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 201\", () => {", + " pm.response.to.have.status(201);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " pm.expect(pm.response.json().userName).to.eql(\"createdtestuser\");", + "});", + "", + "pm.test(\"Response body contains a valid non-null user ID (the ID of the user which was created)\", () => {", + " pm.expect(pm.response.json().id).to.not.be.null;", + "});", + "", + "pm.collectionVariables.set(\"testUserId\", pm.response.json().id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"userName\": \"createdtestuser\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/bearer/Users", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Users" + ] + } + }, + "response": [] + }, + { + "name": "Read a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the user ID of the user we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testUserId'));", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " pm.expect(pm.response.json().userName).to.eql(\"createdtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/bearer/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + }, + { + "name": "Read all users", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains user with userName \\\"createdtestuser\\\"\", () => {", + " var resources = pm.response.json().Resources.map(x => x.userName);", + " pm.expect(resources).to.contain(\"createdtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/bearer/Users", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Users" + ] + } + }, + "response": [] + }, + { + "name": "Update a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the user ID of the user we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testUserId'));", + "});", + "", + "pm.test(\"Response body contains user with displayName \\\"updatedtestuser\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"updatedtestuser\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"updatedtestuser\",\n \"active\": false\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/bearer/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + }, + { + "name": "Delete a single user", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 204\", () => {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"userName\": \"updatedtestuser\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/bearer/Users/{{testUserId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Users", + "{{testUserId}}" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + }, + { + "name": "Groups", + "item": [ + { + "name": "Create a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 201\", () => {", + " pm.response.to.have.status(201);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"createdtestgroup\");", + "});", + "", + "pm.test(\"Response body contains a valid non-null group ID (the ID of the group which was created)\", () => {", + " pm.expect(pm.response.json().id).to.not.be.null;", + "});", + "", + "pm.collectionVariables.set(\"testGroupId\", pm.response.json().id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json", + "type": "default" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"createdtestgroup\",\n \"members\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/bearer/Groups", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Groups" + ] + } + }, + "response": [] + }, + { + "name": "Read a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the group ID of the group we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testGroupId'));", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"createdtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/bearer/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + }, + { + "name": "Read all groups", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json().Resources).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"createdtestgroup\\\"\", () => {", + " var resources = pm.response.json().Resources.map(x => x.displayName);", + " pm.expect(resources).to.contain(\"createdtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{url}}/bearer/Groups", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Groups" + ] + } + }, + "response": [] + }, + { + "name": "Update a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 200\", () => {", + " pm.response.to.have.status(200);", + "});", + "", + "pm.test(\"Response body is not empty\", () => {", + " pm.expect(pm.response.json()).to.not.be.empty;", + "});", + "", + "pm.test(\"Response body contains the group ID of the group we want to read\", () => {", + " pm.expect(pm.response.json().id).to.eql(pm.collectionVariables.get('testGroupId'));", + "});", + "", + "pm.test(\"Response body contains group with displayName \\\"updatedtestgroup\\\"\", () => {", + " pm.expect(pm.response.json().displayName).to.eql(\"updatedtestgroup\");", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"displayName\": \"updatedtestgroup\",\n \"members\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{url}}/bearer/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + }, + { + "name": "Delete a single group", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response status code is 204\", () => {", + " pm.response.to.have.status(204);", + "});" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "DELETE", + "header": [], + "url": { + "raw": "{{url}}/bearer/Groups/{{testGroupId}}", + "host": [ + "{{url}}" + ], + "path": [ + "bearer", + "Groups", + "{{testGroupId}}" + ] + } + }, + "response": [] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] + } + ], + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiYWRtaW4ifQ.Oetm7xvhkYbiItRiqNx-z7LZ6ZkmDe1z_95igbPUSjA", + "type": "string" + } + ] + }, + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "testUserId", + "value": null + }, + { + "key": "testGroupId", + "value": null + }, + { + "key": "url", + "value": "http://localhost:8888/index.php/apps/scimserviceprovider", + "type": "default" + } + ] +} \ No newline at end of file