From eb3f69b0bb5b8461bc56df9a6af8cf3979bd5488 Mon Sep 17 00:00:00 2001
From: Kevin J Gao <32936811+gaokevin1@users.noreply.github.com>
Date: Sat, 4 Jan 2025 23:41:59 -0800
Subject: [PATCH] feat: Added JWK Caching and Support for Laravel 11 (#32)
---
.github/workflows/phpunit.yml | 31 +
README.md | 56 +-
composer.json | 1 -
composer.lock | 2354 +----------------
phpunit.xml | 8 +
sample/dashboard.php | 1 +
src/SDK/API.php | 42 +-
src/SDK/Auth/SSO.php | 12 +-
src/SDK/Cache/APCuCache.php | 21 +
src/SDK/Cache/CacheInterface.php | 10 +
src/SDK/Cache/NullCache.php | 21 +
src/SDK/Configuration/SDKConfig.php | 53 +-
src/SDK/DescopeSDK.php | 132 +-
src/SDK/Exception/ValidationException.php | 57 +
.../Password/UserPasswordBcrypt.php | 2 +-
.../Password/UserPasswordDjango.php | 2 +-
.../Password/UserPasswordFirebase.php | 2 +-
.../Management/Password/UserPasswordMD5.php | 41 +
.../Password/UserPasswordPHPass.php | 2 +-
.../Password/UserPasswordPbkdf2.php | 2 +-
src/SDK/Management/Role.php | 96 +
src/SDK/Token/Extractor.php | 232 +-
src/SDK/Token/Verifier.php | 181 +-
src/tests/DescopeSDKTest.php | 46 +-
src/tests/Management/UserPwdTest.php | 14 +
src/tests/Management/UserTest.php | 3 -
26 files changed, 897 insertions(+), 2525 deletions(-)
create mode 100644 .github/workflows/phpunit.yml
create mode 100644 phpunit.xml
create mode 100644 src/SDK/Cache/APCuCache.php
create mode 100644 src/SDK/Cache/CacheInterface.php
create mode 100644 src/SDK/Cache/NullCache.php
create mode 100644 src/SDK/Exception/ValidationException.php
create mode 100644 src/SDK/Management/Password/UserPasswordMD5.php
create mode 100644 src/SDK/Management/Role.php
diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml
new file mode 100644
index 0000000..101487b
--- /dev/null
+++ b/.github/workflows/phpunit.yml
@@ -0,0 +1,31 @@
+name: PHP Unit Tests
+
+on:
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ test:
+ runs-on: ubuntu-latest
+
+ env:
+ DESCOPE_PROJECT_ID: ${{ vars.DESCOPE_PROJECT_ID }}
+
+ strategy:
+ matrix:
+ php-version: [8.1, 7.4]
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Set up PHP
+ uses: shivammathur/setup-php@v2
+ with:
+ php-version: ${{ matrix.php-version }}
+
+ - name: Install dependencies
+ run: composer install
+
+ - name: Run tests
+ run: vendor/bin/phpunit --configuration phpunit.xml
\ No newline at end of file
diff --git a/README.md b/README.md
index 3778e3b..03a24d9 100644
--- a/README.md
+++ b/README.md
@@ -41,7 +41,61 @@ $descopeSDK = new DescopeSDK([
]);
```
-This SDK will easily allow you to handle Descope JWT tokens with the following built-in functions:
+### Caching Mechanism
+
+The Descope PHP SDK uses a caching mechanism to store frequently accessed data, such as JSON Web Key Sets (JWKs) for session token validation. By default, the SDK uses **APCu** for caching, provided it is enabled and configured in your environment. If APCu is not available, and no other caching mechanism is provided, caching is disabled.
+
+By using the `CacheInterface`, you can integrate the Descope PHP SDK with any caching mechanism that suits your application, ensuring optimal performance in both small and large-scale deployments.
+
+#### Custom Caching with `CacheInterface`
+
+The SDK allows you to provide a custom caching mechanism by implementing the `CacheInterface`. This interface defines three methods that any cache implementation should support:
+
+- `get(string $key)`: Retrieve a value by key.
+- `set(string $key, $value, int $ttl = 3600): bool`: Store a value with a specified time-to-live (TTL).
+- `delete(string $key): bool`: Remove a value by key.
+
+You can provide your custom caching implementation by creating a class that implements `CacheInterface`. Here’s an example using Laravel’s cache system:
+
+```php
+namespace App\Cache;
+
+use Descope\SDK\Cache\CacheInterface;
+use Illuminate\Support\Facades\Cache;
+
+class LaravelCache implements CacheInterface
+{
+ public function get(string $key)
+ {
+ return Cache::get($key);
+ }
+
+ public function set(string $key, $value, int $ttl = 3600): bool
+ {
+ // Laravel TTL is in minutes
+ return Cache::put($key, $value, max(1, ceil($ttl / 60)));
+ }
+
+ public function delete(string $key): bool
+ {
+ return Cache::forget($key);
+ }
+}
+```
+
+To use the Laravel cache in the SDK:
+
+```php
+use Descope\SDK\DescopeSDK;
+use App\Cache\LaravelCache;
+
+$descopeSDK = new DescopeSDK([
+ 'projectId' => $_ENV['DESCOPE_PROJECT_ID'],
+ 'managementKey' => $_ENV['DESCOPE_MANAGEMENT_KEY'],
+], new LaravelCache());
+```
+
+Once you've configured your caching, you're ready to use the SDK. This SDK will easily allow you integrate Descope functionality with the following built-in functions:
## Password Authentication
diff --git a/composer.json b/composer.json
index 79020bc..dd29eb7 100644
--- a/composer.json
+++ b/composer.json
@@ -16,7 +16,6 @@
],
"require": {
"php": "^7.3 || ^8.0",
- "web-token/jwt-framework": "2.2.11 as 2.3.0",
"guzzlehttp/guzzle": "7.9.2 as 7.9.3",
"paragonie/constant_time_encoding": "^2.7.0",
"vlucas/phpdotenv": "^5.6.1"
diff --git a/composer.lock b/composer.lock
index d26365e..9f6cc75 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,144 +4,8 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "35e70dbd77fca8551fdaf29f9d79b765",
+ "content-hash": "445d03808865bcc00bd5191e7902ce33",
"packages": [
- {
- "name": "brick/math",
- "version": "0.9.3",
- "source": {
- "type": "git",
- "url": "https://github.com/brick/math.git",
- "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/brick/math/zipball/ca57d18f028f84f777b2168cd1911b0dee2343ae",
- "reference": "ca57d18f028f84f777b2168cd1911b0dee2343ae",
- "shasum": ""
- },
- "require": {
- "ext-json": "*",
- "php": "^7.1 || ^8.0"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "^2.2",
- "phpunit/phpunit": "^7.5.15 || ^8.5 || ^9.0",
- "vimeo/psalm": "4.9.2"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Brick\\Math\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "Arbitrary-precision arithmetic library",
- "keywords": [
- "Arbitrary-precision",
- "BigInteger",
- "BigRational",
- "arithmetic",
- "bigdecimal",
- "bignum",
- "brick",
- "math"
- ],
- "support": {
- "issues": "https://github.com/brick/math/issues",
- "source": "https://github.com/brick/math/tree/0.9.3"
- },
- "funding": [
- {
- "url": "https://github.com/BenMorel",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/brick/math",
- "type": "tidelift"
- }
- ],
- "time": "2021-08-15T20:50:18+00:00"
- },
- {
- "name": "fgrosse/phpasn1",
- "version": "v2.5.0",
- "source": {
- "type": "git",
- "url": "https://github.com/fgrosse/PHPASN1.git",
- "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b",
- "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b",
- "shasum": ""
- },
- "require": {
- "php": "^7.1 || ^8.0"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "~2.0",
- "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
- },
- "suggest": {
- "ext-bcmath": "BCmath is the fallback extension for big integer calculations",
- "ext-curl": "For loading OID information from the web if they have not bee defined statically",
- "ext-gmp": "GMP is the preferred extension for big integer calculations",
- "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "2.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "FG\\": "lib/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Friedrich Große",
- "email": "friedrich.grosse@gmail.com",
- "homepage": "https://github.com/FGrosse",
- "role": "Author"
- },
- {
- "name": "All contributors",
- "homepage": "https://github.com/FGrosse/PHPASN1/contributors"
- }
- ],
- "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.",
- "homepage": "https://github.com/FGrosse/PHPASN1",
- "keywords": [
- "DER",
- "asn.1",
- "asn1",
- "ber",
- "binary",
- "decoding",
- "encoding",
- "x.509",
- "x.690",
- "x509",
- "x690"
- ],
- "support": {
- "issues": "https://github.com/fgrosse/PHPASN1/issues",
- "source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0"
- },
- "abandoned": true,
- "time": "2022-12-19T11:08:26+00:00"
- },
{
"name": "graham-campbell/result-type",
"version": "v1.1.3",
@@ -332,16 +196,16 @@
},
{
"name": "guzzlehttp/promises",
- "version": "2.0.3",
+ "version": "2.0.4",
"source": {
"type": "git",
"url": "https://github.com/guzzle/promises.git",
- "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
+ "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
- "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
+ "url": "https://api.github.com/repos/guzzle/promises/zipball/f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
+ "reference": "f9c436286ab2892c7db7be8c8da4ef61ccf7b455",
"shasum": ""
},
"require": {
@@ -395,7 +259,7 @@
],
"support": {
"issues": "https://github.com/guzzle/promises/issues",
- "source": "https://github.com/guzzle/promises/tree/2.0.3"
+ "source": "https://github.com/guzzle/promises/tree/2.0.4"
},
"funding": [
{
@@ -411,7 +275,7 @@
"type": "tidelift"
}
],
- "time": "2024-07-18T10:29:17+00:00"
+ "time": "2024-10-17T10:06:22+00:00"
},
{
"name": "guzzlehttp/psr7",
@@ -671,104 +535,6 @@
],
"time": "2024-07-20T21:41:07+00:00"
},
- {
- "name": "psr/container",
- "version": "1.1.2",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/container.git",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/container/zipball/513e0666f7216c7459170d56df27dfcefe1689ea",
- "reference": "513e0666f7216c7459170d56df27dfcefe1689ea",
- "shasum": ""
- },
- "require": {
- "php": ">=7.4.0"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Psr\\Container\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common Container Interface (PHP FIG PSR-11)",
- "homepage": "https://github.com/php-fig/container",
- "keywords": [
- "PSR-11",
- "container",
- "container-interface",
- "container-interop",
- "psr"
- ],
- "support": {
- "issues": "https://github.com/php-fig/container/issues",
- "source": "https://github.com/php-fig/container/tree/1.1.2"
- },
- "time": "2021-11-05T16:50:12+00:00"
- },
- {
- "name": "psr/event-dispatcher",
- "version": "1.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/event-dispatcher.git",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0",
- "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\EventDispatcher\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "http://www.php-fig.org/"
- }
- ],
- "description": "Standard interfaces for event handling.",
- "keywords": [
- "events",
- "psr",
- "psr-14"
- ],
- "support": {
- "issues": "https://github.com/php-fig/event-dispatcher/issues",
- "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0"
- },
- "time": "2019-01-08T18:20:26+00:00"
- },
{
"name": "psr/http-client",
"version": "1.0.3",
@@ -929,1487 +695,31 @@
},
"time": "2023-04-04T09:54:51+00:00"
},
- {
- "name": "psr/log",
- "version": "1.1.4",
- "source": {
- "type": "git",
- "url": "https://github.com/php-fig/log.git",
- "reference": "d49695b909c3b7628b6289db5479a1c204601f11"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
- "reference": "d49695b909c3b7628b6289db5479a1c204601f11",
- "shasum": ""
- },
- "require": {
- "php": ">=5.3.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "1.1.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "Psr\\Log\\": "Psr/Log/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "PHP-FIG",
- "homepage": "https://www.php-fig.org/"
- }
- ],
- "description": "Common interface for logging libraries",
- "homepage": "https://github.com/php-fig/log",
- "keywords": [
- "log",
- "psr",
- "psr-3"
- ],
- "support": {
- "source": "https://github.com/php-fig/log/tree/1.1.4"
- },
- "time": "2021-05-03T11:20:27+00:00"
- },
{
"name": "ralouphie/getallheaders",
"version": "3.0.3",
"source": {
"type": "git",
"url": "https://github.com/ralouphie/getallheaders.git",
- "reference": "120b605dfeb996808c31b6477290a714d356e822"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
- "reference": "120b605dfeb996808c31b6477290a714d356e822",
- "shasum": ""
- },
- "require": {
- "php": ">=5.6"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "^2.1",
- "phpunit/phpunit": "^5 || ^6.5"
- },
- "type": "library",
- "autoload": {
- "files": [
- "src/getallheaders.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Ralph Khattar",
- "email": "ralph.khattar@gmail.com"
- }
- ],
- "description": "A polyfill for getallheaders.",
- "support": {
- "issues": "https://github.com/ralouphie/getallheaders/issues",
- "source": "https://github.com/ralouphie/getallheaders/tree/develop"
- },
- "time": "2019-03-08T08:55:37+00:00"
- },
- {
- "name": "spomky-labs/aes-key-wrap",
- "version": "v6.0.0",
- "source": {
- "type": "git",
- "url": "https://github.com/Spomky-Labs/aes-key-wrap.git",
- "reference": "97388255a37ad6fb1ed332d07e61fa2b7bb62e0d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Spomky-Labs/aes-key-wrap/zipball/97388255a37ad6fb1ed332d07e61fa2b7bb62e0d",
- "reference": "97388255a37ad6fb1ed332d07e61fa2b7bb62e0d",
- "shasum": ""
- },
- "require": {
- "ext-mbstring": "*",
- "lib-openssl": "*",
- "php": ">=7.2",
- "thecodingmachine/safe": "^1.1"
- },
- "require-dev": {
- "php-coveralls/php-coveralls": "^2.0",
- "phpstan/phpstan": "^0.12",
- "phpstan/phpstan-beberlei-assert": "^0.12",
- "phpstan/phpstan-deprecation-rules": "^0.12",
- "phpstan/phpstan-phpunit": "^0.12",
- "phpstan/phpstan-strict-rules": "^0.12",
- "phpunit/phpunit": "^7.0|^8.0|^9.0",
- "thecodingmachine/phpstan-safe-rule": "^1.0"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "5.0.x-dev"
- }
- },
- "autoload": {
- "psr-4": {
- "AESKW\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Florent Morselli",
- "homepage": "https://github.com/Spomky-Labs/aes-key-wrap/contributors"
- }
- ],
- "description": "AES Key Wrap for PHP.",
- "homepage": "https://github.com/Spomky-Labs/aes-key-wrap",
- "keywords": [
- "A128KW",
- "A192KW",
- "A256KW",
- "RFC3394",
- "RFC5649",
- "aes",
- "key",
- "padding",
- "wrap"
- ],
- "support": {
- "issues": "https://github.com/Spomky-Labs/aes-key-wrap/issues",
- "source": "https://github.com/Spomky-Labs/aes-key-wrap/tree/v6.0.0"
- },
- "time": "2020-08-01T14:07:55+00:00"
- },
- {
- "name": "spomky-labs/base64url",
- "version": "v2.0.4",
- "source": {
- "type": "git",
- "url": "https://github.com/Spomky-Labs/base64url.git",
- "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d",
- "reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "require-dev": {
- "phpstan/extension-installer": "^1.0",
- "phpstan/phpstan": "^0.11|^0.12",
- "phpstan/phpstan-beberlei-assert": "^0.11|^0.12",
- "phpstan/phpstan-deprecation-rules": "^0.11|^0.12",
- "phpstan/phpstan-phpunit": "^0.11|^0.12",
- "phpstan/phpstan-strict-rules": "^0.11|^0.12"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Base64Url\\": "src/"
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Florent Morselli",
- "homepage": "https://github.com/Spomky-Labs/base64url/contributors"
- }
- ],
- "description": "Base 64 URL Safe Encoding/Decoding PHP Library",
- "homepage": "https://github.com/Spomky-Labs/base64url",
- "keywords": [
- "base64",
- "rfc4648",
- "safe",
- "url"
- ],
- "support": {
- "issues": "https://github.com/Spomky-Labs/base64url/issues",
- "source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4"
- },
- "funding": [
- {
- "url": "https://github.com/Spomky",
- "type": "github"
- },
- {
- "url": "https://www.patreon.com/FlorentMorselli",
- "type": "patreon"
- }
- ],
- "time": "2020-11-03T09:10:25+00:00"
- },
- {
- "name": "symfony/config",
- "version": "v5.4.40",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/config.git",
- "reference": "d4e1db78421163b98dd9971d247fd0df4a57ee5e"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/config/zipball/d4e1db78421163b98dd9971d247fd0df4a57ee5e",
- "reference": "d4e1db78421163b98dd9971d247fd0df4a57ee5e",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/filesystem": "^4.4|^5.0|^6.0",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-php80": "^1.16",
- "symfony/polyfill-php81": "^1.22"
- },
- "conflict": {
- "symfony/finder": "<4.4"
- },
- "require-dev": {
- "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
- "symfony/finder": "^4.4|^5.0|^6.0",
- "symfony/messenger": "^4.4|^5.0|^6.0",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/yaml": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "symfony/yaml": "To use the yaml reference dumper"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Config\\": ""
- },
- "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": "Helps you find, load, combine, autofill and validate configuration values of any kind",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/config/tree/v5.4.40"
- },
- "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": "2024-05-31T14:33:22+00:00"
- },
- {
- "name": "symfony/console",
- "version": "v5.4.44",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/console.git",
- "reference": "5b5a0aa66e3296e303e22490f90f521551835a83"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/console/zipball/5b5a0aa66e3296e303e22490f90f521551835a83",
- "reference": "5b5a0aa66e3296e303e22490f90f521551835a83",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php73": "^1.9",
- "symfony/polyfill-php80": "^1.16",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/string": "^5.1|^6.0"
- },
- "conflict": {
- "psr/log": ">=3",
- "symfony/dependency-injection": "<4.4",
- "symfony/dotenv": "<5.1",
- "symfony/event-dispatcher": "<4.4",
- "symfony/lock": "<4.4",
- "symfony/process": "<4.4"
- },
- "provide": {
- "psr/log-implementation": "1.0|2.0"
- },
- "require-dev": {
- "psr/log": "^1|^2",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^4.4|^5.0|^6.0",
- "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
- "symfony/lock": "^4.4|^5.0|^6.0",
- "symfony/process": "^4.4|^5.0|^6.0",
- "symfony/var-dumper": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "psr/log": "For using the console logger",
- "symfony/event-dispatcher": "",
- "symfony/lock": "",
- "symfony/process": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Console\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Eases the creation of beautiful and testable command line interfaces",
- "homepage": "https://symfony.com",
- "keywords": [
- "cli",
- "command-line",
- "console",
- "terminal"
- ],
- "support": {
- "source": "https://github.com/symfony/console/tree/v5.4.44"
- },
- "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": "2024-09-20T07:56:40+00:00"
- },
- {
- "name": "symfony/dependency-injection",
- "version": "v5.4.44",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/dependency-injection.git",
- "reference": "23eb9f3803a931aef16a65f362a9aeb0640a1374"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/23eb9f3803a931aef16a65f362a9aeb0640a1374",
- "reference": "23eb9f3803a931aef16a65f362a9aeb0640a1374",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/container": "^1.1.1",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-php80": "^1.16",
- "symfony/polyfill-php81": "^1.22",
- "symfony/service-contracts": "^1.1.6|^2"
- },
- "conflict": {
- "ext-psr": "<1.1|>=2",
- "symfony/config": "<5.3",
- "symfony/finder": "<4.4",
- "symfony/proxy-manager-bridge": "<4.4",
- "symfony/yaml": "<4.4.26"
- },
- "provide": {
- "psr/container-implementation": "1.0",
- "symfony/service-implementation": "1.0|2.0"
- },
- "require-dev": {
- "symfony/config": "^5.3|^6.0",
- "symfony/expression-language": "^4.4|^5.0|^6.0",
- "symfony/yaml": "^4.4.26|^5.0|^6.0"
- },
- "suggest": {
- "symfony/config": "",
- "symfony/expression-language": "For using expressions in service container configuration",
- "symfony/finder": "For using double-star glob patterns or when GLOB_BRACE portability is required",
- "symfony/proxy-manager-bridge": "Generate service proxies to lazy load them",
- "symfony/yaml": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\DependencyInjection\\": ""
- },
- "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": "Allows you to standardize and centralize the way objects are constructed in your application",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/dependency-injection/tree/v5.4.44"
- },
- "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": "2024-09-12T20:01:35+00:00"
- },
- {
- "name": "symfony/deprecation-contracts",
- "version": "v2.5.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d",
- "reference": "80d075412b557d41002320b96a096ca65aa2c98d",
- "shasum": ""
- },
- "require": {
- "php": ">=7.1"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "files": [
- "function.php"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "A generic function and convention to trigger deprecation notices",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2023-01-24T14:02:46+00:00"
- },
- {
- "name": "symfony/error-handler",
- "version": "v5.4.42",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/error-handler.git",
- "reference": "db15ba0fd50890156ed40087ccedc7851a1f5b76"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/error-handler/zipball/db15ba0fd50890156ed40087ccedc7851a1f5b76",
- "reference": "db15ba0fd50890156ed40087ccedc7851a1f5b76",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/log": "^1|^2|^3",
- "symfony/var-dumper": "^4.4|^5.0|^6.0"
- },
- "require-dev": {
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/http-kernel": "^4.4|^5.0|^6.0",
- "symfony/serializer": "^4.4|^5.0|^6.0"
- },
- "bin": [
- "Resources/bin/patch-type-declarations"
- ],
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\ErrorHandler\\": ""
- },
- "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 manage errors and ease debugging PHP code",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/error-handler/tree/v5.4.42"
- },
- "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": "2024-07-23T12:34:05+00:00"
- },
- {
- "name": "symfony/event-dispatcher",
- "version": "v5.4.40",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/event-dispatcher.git",
- "reference": "a54e2a8a114065f31020d6a89ede83e34c3b27a4"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/a54e2a8a114065f31020d6a89ede83e34c3b27a4",
- "reference": "a54e2a8a114065f31020d6a89ede83e34c3b27a4",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/event-dispatcher-contracts": "^2|^3",
- "symfony/polyfill-php80": "^1.16"
- },
- "conflict": {
- "symfony/dependency-injection": "<4.4"
- },
- "provide": {
- "psr/event-dispatcher-implementation": "1.0",
- "symfony/event-dispatcher-implementation": "2.0"
- },
- "require-dev": {
- "psr/log": "^1|^2|^3",
- "symfony/config": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^4.4|^5.0|^6.0",
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/expression-language": "^4.4|^5.0|^6.0",
- "symfony/http-foundation": "^4.4|^5.0|^6.0",
- "symfony/service-contracts": "^1.1|^2|^3",
- "symfony/stopwatch": "^4.4|^5.0|^6.0"
- },
- "suggest": {
- "symfony/dependency-injection": "",
- "symfony/http-kernel": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\EventDispatcher\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.40"
- },
- "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": "2024-05-31T14:33:22+00:00"
- },
- {
- "name": "symfony/event-dispatcher-contracts",
- "version": "v2.5.3",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
- "reference": "540f4c73e87fd0c71ca44a6aa305d024ac68cb73",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/event-dispatcher": "^1"
- },
- "suggest": {
- "symfony/event-dispatcher-implementation": ""
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
- "thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
- }
- },
- "autoload": {
- "psr-4": {
- "Symfony\\Contracts\\EventDispatcher\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Generic abstractions related to dispatching event",
- "homepage": "https://symfony.com",
- "keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
- ],
- "support": {
- "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.3"
- },
- "funding": [
- {
- "url": "https://symfony.com/sponsor",
- "type": "custom"
- },
- {
- "url": "https://github.com/fabpot",
- "type": "github"
- },
- {
- "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
- "type": "tidelift"
- }
- ],
- "time": "2024-01-23T13:51:25+00:00"
- },
- {
- "name": "symfony/filesystem",
- "version": "v5.4.44",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/filesystem.git",
- "reference": "76c3818964e9d32be3862c9318ae3ba9aa280ddc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/filesystem/zipball/76c3818964e9d32be3862c9318ae3ba9aa280ddc",
- "reference": "76c3818964e9d32be3862c9318ae3ba9aa280ddc",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/polyfill-ctype": "~1.8",
- "symfony/polyfill-mbstring": "~1.8",
- "symfony/polyfill-php80": "^1.16"
- },
- "require-dev": {
- "symfony/process": "^5.4|^6.4"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\Filesystem\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides basic utilities for the filesystem",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/filesystem/tree/v5.4.44"
- },
- "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": "2024-09-16T14:52:48+00:00"
- },
- {
- "name": "symfony/http-foundation",
- "version": "v5.4.44",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/http-foundation.git",
- "reference": "ae0d217e5932aa0b70ddb4cf7822cc76d48aee53"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ae0d217e5932aa0b70ddb4cf7822cc76d48aee53",
- "reference": "ae0d217e5932aa0b70ddb4cf7822cc76d48aee53",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/polyfill-mbstring": "~1.1",
- "symfony/polyfill-php80": "^1.16"
- },
- "require-dev": {
- "predis/predis": "^1.0|^2.0",
- "symfony/cache": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^5.4|^6.0",
- "symfony/expression-language": "^4.4|^5.0|^6.0",
- "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4",
- "symfony/mime": "^4.4|^5.0|^6.0",
- "symfony/rate-limiter": "^5.2|^6.0"
- },
- "suggest": {
- "symfony/mime": "To use the file extension guesser"
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\HttpFoundation\\": ""
- },
- "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": "Defines an object-oriented layer for the HTTP specification",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/http-foundation/tree/v5.4.44"
- },
- "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": "2024-09-15T07:55:06+00:00"
- },
- {
- "name": "symfony/http-kernel",
- "version": "v5.4.44",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/http-kernel.git",
- "reference": "788dcf72d9af7432a886aa3b0c5904d68087ba13"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/http-kernel/zipball/788dcf72d9af7432a886aa3b0c5904d68087ba13",
- "reference": "788dcf72d9af7432a886aa3b0c5904d68087ba13",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2.5",
- "psr/log": "^1|^2",
- "symfony/deprecation-contracts": "^2.1|^3",
- "symfony/error-handler": "^4.4|^5.0|^6.0",
- "symfony/event-dispatcher": "^5.0|^6.0",
- "symfony/http-foundation": "^5.4.21|^6.2.7",
- "symfony/polyfill-ctype": "^1.8",
- "symfony/polyfill-php73": "^1.9",
- "symfony/polyfill-php80": "^1.16"
- },
- "conflict": {
- "symfony/browser-kit": "<5.4",
- "symfony/cache": "<5.0",
- "symfony/config": "<5.0",
- "symfony/console": "<4.4",
- "symfony/dependency-injection": "<5.3",
- "symfony/doctrine-bridge": "<5.0",
- "symfony/form": "<5.0",
- "symfony/http-client": "<5.0",
- "symfony/mailer": "<5.0",
- "symfony/messenger": "<5.0",
- "symfony/translation": "<5.0",
- "symfony/twig-bridge": "<5.0",
- "symfony/validator": "<5.0",
- "twig/twig": "<2.13"
- },
- "provide": {
- "psr/log-implementation": "1.0|2.0"
- },
- "require-dev": {
- "psr/cache": "^1.0|^2.0|^3.0",
- "symfony/browser-kit": "^5.4|^6.0",
- "symfony/config": "^5.0|^6.0",
- "symfony/console": "^4.4|^5.0|^6.0",
- "symfony/css-selector": "^4.4|^5.0|^6.0",
- "symfony/dependency-injection": "^5.3|^6.0",
- "symfony/dom-crawler": "^4.4|^5.0|^6.0",
- "symfony/expression-language": "^4.4|^5.0|^6.0",
- "symfony/finder": "^4.4|^5.0|^6.0",
- "symfony/http-client-contracts": "^1.1|^2|^3",
- "symfony/process": "^4.4|^5.0|^6.0",
- "symfony/routing": "^4.4|^5.0|^6.0",
- "symfony/stopwatch": "^4.4|^5.0|^6.0",
- "symfony/translation": "^4.4|^5.0|^6.0",
- "symfony/translation-contracts": "^1.1|^2|^3",
- "symfony/var-dumper": "^4.4.31|^5.4",
- "twig/twig": "^2.13|^3.0.4"
- },
- "suggest": {
- "symfony/browser-kit": "",
- "symfony/config": "",
- "symfony/console": "",
- "symfony/dependency-injection": ""
- },
- "type": "library",
- "autoload": {
- "psr-4": {
- "Symfony\\Component\\HttpKernel\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Fabien Potencier",
- "email": "fabien@symfony.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Provides a structured process for converting a Request into a Response",
- "homepage": "https://symfony.com",
- "support": {
- "source": "https://github.com/symfony/http-kernel/tree/v5.4.44"
- },
- "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": "2024-09-21T05:47:58+00:00"
- },
- {
- "name": "symfony/polyfill-ctype",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-ctype.git",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
- "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-ctype": "*"
- },
- "suggest": {
- "ext-ctype": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Ctype\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Gert de Pagter",
- "email": "BackEndTea@gmail.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for ctype functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "ctype",
- "polyfill",
- "portable"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.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": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-intl-grapheme",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-grapheme.git",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
- },
- "autoload": {
- "files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Intl\\Grapheme\\": ""
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
- }
- ],
- "description": "Symfony polyfill for intl's grapheme_* functions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "grapheme",
- "intl",
- "polyfill",
- "portable",
- "shim"
- ],
- "support": {
- "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.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": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-intl-normalizer",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-intl-normalizer.git",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c",
- "reference": "3833d7255cc303546435cb650316bff708a1c75c",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "suggest": {
- "ext-intl": "For best performance"
- },
- "type": "library",
- "extra": {
- "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.31.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": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-mbstring",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-mbstring.git",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
- "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "provide": {
- "ext-mbstring": "*"
- },
- "suggest": {
- "ext-mbstring": "For best performance"
- },
- "type": "library",
- "extra": {
- "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.31.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": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-php73",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php73.git",
- "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
- "reference": "0f68c03565dcaaf25a890667542e8bd75fe7e5bb",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "type": "library",
- "extra": {
- "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.31.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": "2024-09-09T11:45:10+00:00"
- },
- {
- "name": "symfony/polyfill-php80",
- "version": "v1.31.0",
- "source": {
- "type": "git",
- "url": "https://github.com/symfony/polyfill-php80.git",
- "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
+ "reference": "120b605dfeb996808c31b6477290a714d356e822"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
- "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
+ "reference": "120b605dfeb996808c31b6477290a714d356e822",
"shasum": ""
},
"require": {
- "php": ">=7.2"
+ "php": ">=5.6"
},
- "type": "library",
- "extra": {
- "thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
- }
+ "require-dev": {
+ "php-coveralls/php-coveralls": "^2.1",
+ "phpunit/phpunit": "^5 || ^6.5"
},
+ "type": "library",
"autoload": {
"files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php80\\": ""
- },
- "classmap": [
- "Resources/stubs"
+ "src/getallheaders.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -2418,78 +728,47 @@
],
"authors": [
{
- "name": "Ion Bazan",
- "email": "ion.bazan@gmail.com"
- },
- {
- "name": "Nicolas Grekas",
- "email": "p@tchwork.com"
- },
- {
- "name": "Symfony Community",
- "homepage": "https://symfony.com/contributors"
+ "name": "Ralph Khattar",
+ "email": "ralph.khattar@gmail.com"
}
],
- "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
- "homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
+ "description": "A polyfill for getallheaders.",
"support": {
- "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
+ "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": "2024-09-09T11:45:10+00:00"
+ "time": "2019-03-08T08:55:37+00:00"
},
{
- "name": "symfony/polyfill-php81",
- "version": "v1.31.0",
+ "name": "symfony/deprecation-contracts",
+ "version": "v2.5.4",
"source": {
"type": "git",
- "url": "https://github.com/symfony/polyfill-php81.git",
- "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
+ "url": "https://github.com/symfony/deprecation-contracts.git",
+ "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
- "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918",
+ "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918",
"shasum": ""
},
"require": {
- "php": ">=7.2"
+ "php": ">=7.1"
},
"type": "library",
"extra": {
"thanks": {
- "name": "symfony/polyfill",
- "url": "https://github.com/symfony/polyfill"
+ "url": "https://github.com/symfony/contracts",
+ "name": "symfony/contracts"
+ },
+ "branch-alias": {
+ "dev-main": "2.5-dev"
}
},
"autoload": {
"files": [
- "bootstrap.php"
- ],
- "psr-4": {
- "Symfony\\Polyfill\\Php81\\": ""
- },
- "classmap": [
- "Resources/stubs"
+ "function.php"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -2506,16 +785,10 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
+ "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
- "keywords": [
- "compatibility",
- "polyfill",
- "portable",
- "shim"
- ],
"support": {
- "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4"
},
"funding": [
{
@@ -2531,46 +804,44 @@
"type": "tidelift"
}
],
- "time": "2024-09-09T11:45:10+00:00"
+ "time": "2024-09-25T14:11:13+00:00"
},
{
- "name": "symfony/service-contracts",
- "version": "v2.5.3",
+ "name": "symfony/polyfill-ctype",
+ "version": "v1.31.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/service-contracts.git",
- "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3"
+ "url": "https://github.com/symfony/polyfill-ctype.git",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/a2329596ddc8fd568900e3fc76cba42489ecc7f3",
- "reference": "a2329596ddc8fd568900e3fc76cba42489ecc7f3",
+ "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
+ "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "psr/container": "^1.1",
- "symfony/deprecation-contracts": "^2.1|^3"
+ "php": ">=7.2"
},
- "conflict": {
- "ext-psr": "<1.1|>=2"
+ "provide": {
+ "ext-ctype": "*"
},
"suggest": {
- "symfony/service-implementation": ""
+ "ext-ctype": "For best performance"
},
"type": "library",
"extra": {
- "branch-alias": {
- "dev-main": "2.5-dev"
- },
"thanks": {
- "name": "symfony/contracts",
- "url": "https://github.com/symfony/contracts"
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
}
},
"autoload": {
+ "files": [
+ "bootstrap.php"
+ ],
"psr-4": {
- "Symfony\\Contracts\\Service\\": ""
+ "Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
@@ -2579,26 +850,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": "Generic abstractions related to writing services",
+ "description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
- "abstractions",
- "contracts",
- "decoupling",
- "interfaces",
- "interoperability",
- "standards"
+ "compatibility",
+ "ctype",
+ "polyfill",
+ "portable"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v2.5.3"
+ "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
@@ -2614,50 +883,45 @@
"type": "tidelift"
}
],
- "time": "2023-04-21T15:04:16+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
- "name": "symfony/string",
- "version": "v5.4.44",
+ "name": "symfony/polyfill-mbstring",
+ "version": "v1.31.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/string.git",
- "reference": "832caa16b6d9aac6bf11747315225f5aba384c24"
+ "url": "https://github.com/symfony/polyfill-mbstring.git",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/string/zipball/832caa16b6d9aac6bf11747315225f5aba384c24",
- "reference": "832caa16b6d9aac6bf11747315225f5aba384c24",
+ "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341",
+ "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341",
"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"
+ "php": ">=7.2"
},
- "conflict": {
- "symfony/translation-contracts": ">=3.0"
+ "provide": {
+ "ext-mbstring": "*"
},
- "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"
+ "suggest": {
+ "ext-mbstring": "For best performance"
},
"type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
"autoload": {
"files": [
- "Resources/functions.php"
+ "bootstrap.php"
],
"psr-4": {
- "Symfony\\Component\\String\\": ""
- },
- "exclude-from-classmap": [
- "/Tests/"
- ]
+ "Symfony\\Polyfill\\Mbstring\\": ""
+ }
},
"notification-url": "https://packagist.org/downloads/",
"license": [
@@ -2673,18 +937,17 @@
"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": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
- "grapheme",
- "i18n",
- "string",
- "unicode",
- "utf-8",
- "utf8"
+ "compatibility",
+ "mbstring",
+ "polyfill",
+ "portable",
+ "shim"
],
"support": {
- "source": "https://github.com/symfony/string/tree/v5.4.44"
+ "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0"
},
"funding": [
{
@@ -2700,56 +963,41 @@
"type": "tidelift"
}
],
- "time": "2024-09-20T07:56:40+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
- "name": "symfony/var-dumper",
- "version": "v5.4.43",
+ "name": "symfony/polyfill-php80",
+ "version": "v1.31.0",
"source": {
"type": "git",
- "url": "https://github.com/symfony/var-dumper.git",
- "reference": "6be6a6a8af4818564e3726fc65cf936f34743cef"
+ "url": "https://github.com/symfony/polyfill-php80.git",
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6be6a6a8af4818564e3726fc65cf936f34743cef",
- "reference": "6be6a6a8af4818564e3726fc65cf936f34743cef",
+ "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
+ "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8",
"shasum": ""
},
"require": {
- "php": ">=7.2.5",
- "symfony/polyfill-mbstring": "~1.0",
- "symfony/polyfill-php80": "^1.16"
- },
- "conflict": {
- "symfony/console": "<4.4"
- },
- "require-dev": {
- "ext-iconv": "*",
- "symfony/console": "^4.4|^5.0|^6.0",
- "symfony/http-kernel": "^4.4|^5.0|^6.0",
- "symfony/process": "^4.4|^5.0|^6.0",
- "symfony/uid": "^5.1|^6.0",
- "twig/twig": "^2.13|^3.0.4"
- },
- "suggest": {
- "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).",
- "ext-intl": "To show region name in time zone dump",
- "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script"
+ "php": ">=7.2"
},
- "bin": [
- "Resources/bin/var-dump-server"
- ],
"type": "library",
+ "extra": {
+ "thanks": {
+ "url": "https://github.com/symfony/polyfill",
+ "name": "symfony/polyfill"
+ }
+ },
"autoload": {
"files": [
- "Resources/functions/dump.php"
+ "bootstrap.php"
],
"psr-4": {
- "Symfony\\Component\\VarDumper\\": ""
+ "Symfony\\Polyfill\\Php80\\": ""
},
- "exclude-from-classmap": [
- "/Tests/"
+ "classmap": [
+ "Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
@@ -2757,6 +1005,10 @@
"MIT"
],
"authors": [
+ {
+ "name": "Ion Bazan",
+ "email": "ion.bazan@gmail.com"
+ },
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
@@ -2766,14 +1018,16 @@
"homepage": "https://symfony.com/contributors"
}
],
- "description": "Provides mechanisms for walking through any arbitrary PHP variable",
+ "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
- "debug",
- "dump"
+ "compatibility",
+ "polyfill",
+ "portable",
+ "shim"
],
"support": {
- "source": "https://github.com/symfony/var-dumper/tree/v5.4.43"
+ "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0"
},
"funding": [
{
@@ -2789,146 +1043,7 @@
"type": "tidelift"
}
],
- "time": "2024-08-30T16:01:46+00:00"
- },
- {
- "name": "thecodingmachine/safe",
- "version": "v1.3.3",
- "source": {
- "type": "git",
- "url": "https://github.com/thecodingmachine/safe.git",
- "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/thecodingmachine/safe/zipball/a8ab0876305a4cdaef31b2350fcb9811b5608dbc",
- "reference": "a8ab0876305a4cdaef31b2350fcb9811b5608dbc",
- "shasum": ""
- },
- "require": {
- "php": ">=7.2"
- },
- "require-dev": {
- "phpstan/phpstan": "^0.12",
- "squizlabs/php_codesniffer": "^3.2",
- "thecodingmachine/phpstan-strict-rules": "^0.12"
- },
- "type": "library",
- "extra": {
- "branch-alias": {
- "dev-master": "0.1-dev"
- }
- },
- "autoload": {
- "files": [
- "deprecated/apc.php",
- "deprecated/libevent.php",
- "deprecated/mssql.php",
- "deprecated/stats.php",
- "lib/special_cases.php",
- "generated/apache.php",
- "generated/apcu.php",
- "generated/array.php",
- "generated/bzip2.php",
- "generated/calendar.php",
- "generated/classobj.php",
- "generated/com.php",
- "generated/cubrid.php",
- "generated/curl.php",
- "generated/datetime.php",
- "generated/dir.php",
- "generated/eio.php",
- "generated/errorfunc.php",
- "generated/exec.php",
- "generated/fileinfo.php",
- "generated/filesystem.php",
- "generated/filter.php",
- "generated/fpm.php",
- "generated/ftp.php",
- "generated/funchand.php",
- "generated/gmp.php",
- "generated/gnupg.php",
- "generated/hash.php",
- "generated/ibase.php",
- "generated/ibmDb2.php",
- "generated/iconv.php",
- "generated/image.php",
- "generated/imap.php",
- "generated/info.php",
- "generated/ingres-ii.php",
- "generated/inotify.php",
- "generated/json.php",
- "generated/ldap.php",
- "generated/libxml.php",
- "generated/lzf.php",
- "generated/mailparse.php",
- "generated/mbstring.php",
- "generated/misc.php",
- "generated/msql.php",
- "generated/mysql.php",
- "generated/mysqli.php",
- "generated/mysqlndMs.php",
- "generated/mysqlndQc.php",
- "generated/network.php",
- "generated/oci8.php",
- "generated/opcache.php",
- "generated/openssl.php",
- "generated/outcontrol.php",
- "generated/password.php",
- "generated/pcntl.php",
- "generated/pcre.php",
- "generated/pdf.php",
- "generated/pgsql.php",
- "generated/posix.php",
- "generated/ps.php",
- "generated/pspell.php",
- "generated/readline.php",
- "generated/rpminfo.php",
- "generated/rrd.php",
- "generated/sem.php",
- "generated/session.php",
- "generated/shmop.php",
- "generated/simplexml.php",
- "generated/sockets.php",
- "generated/sodium.php",
- "generated/solr.php",
- "generated/spl.php",
- "generated/sqlsrv.php",
- "generated/ssdeep.php",
- "generated/ssh2.php",
- "generated/stream.php",
- "generated/strings.php",
- "generated/swoole.php",
- "generated/uodbc.php",
- "generated/uopz.php",
- "generated/url.php",
- "generated/var.php",
- "generated/xdiff.php",
- "generated/xml.php",
- "generated/xmlrpc.php",
- "generated/yaml.php",
- "generated/yaz.php",
- "generated/zip.php",
- "generated/zlib.php"
- ],
- "psr-4": {
- "Safe\\": [
- "lib/",
- "deprecated/",
- "generated/"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "description": "PHP core functions that throw exceptions instead of returning FALSE on error",
- "support": {
- "issues": "https://github.com/thecodingmachine/safe/issues",
- "source": "https://github.com/thecodingmachine/safe/tree/v1.3.3"
- },
- "time": "2020-10-28T17:51:34+00:00"
+ "time": "2024-09-09T11:45:10+00:00"
},
{
"name": "vlucas/phpdotenv",
@@ -3013,183 +1128,6 @@
}
],
"time": "2024-07-20T21:52:34+00:00"
- },
- {
- "name": "web-token/jwt-framework",
- "version": "v2.2.11",
- "source": {
- "type": "git",
- "url": "https://github.com/web-token/jwt-framework.git",
- "reference": "643cced197e32471418bd89e7a44b69fd04eb9de"
- },
- "dist": {
- "type": "zip",
- "url": "https://api.github.com/repos/web-token/jwt-framework/zipball/643cced197e32471418bd89e7a44b69fd04eb9de",
- "reference": "643cced197e32471418bd89e7a44b69fd04eb9de",
- "shasum": ""
- },
- "require": {
- "brick/math": "^0.8.17|^0.9",
- "ext-json": "*",
- "ext-mbstring": "*",
- "ext-openssl": "*",
- "ext-sodium": "*",
- "fgrosse/phpasn1": "^2.0",
- "php": ">=7.2",
- "psr/event-dispatcher": "^1.0",
- "psr/http-client": "^1.0",
- "psr/http-factory": "^1.0",
- "spomky-labs/aes-key-wrap": "^5.0|^6.0",
- "spomky-labs/base64url": "^1.0|^2.0",
- "symfony/config": "^4.2|^5.0",
- "symfony/console": "^4.2|^5.0",
- "symfony/dependency-injection": "^4.2|^5.0",
- "symfony/event-dispatcher": "^4.2|^5.0",
- "symfony/http-kernel": "^4.2|^5.0",
- "symfony/polyfill-mbstring": "^1.12"
- },
- "conflict": {
- "spomky-labs/jose": "*"
- },
- "replace": {
- "web-token/encryption-pack": "self.version",
- "web-token/jwt-bundle": "self.version",
- "web-token/jwt-checker": "self.version",
- "web-token/jwt-console": "self.version",
- "web-token/jwt-core": "self.version",
- "web-token/jwt-easy": "self.version",
- "web-token/jwt-encryption": "self.version",
- "web-token/jwt-encryption-algorithm-aescbc": "self.version",
- "web-token/jwt-encryption-algorithm-aesgcm": "self.version",
- "web-token/jwt-encryption-algorithm-aesgcmkw": "self.version",
- "web-token/jwt-encryption-algorithm-aeskw": "self.version",
- "web-token/jwt-encryption-algorithm-dir": "self.version",
- "web-token/jwt-encryption-algorithm-ecdh-es": "self.version",
- "web-token/jwt-encryption-algorithm-experimental": "self.version",
- "web-token/jwt-encryption-algorithm-pbes2": "self.version",
- "web-token/jwt-encryption-algorithm-rsa": "self.version",
- "web-token/jwt-key-mgmt": "self.version",
- "web-token/jwt-nested-token": "self.version",
- "web-token/jwt-signature": "self.version",
- "web-token/jwt-signature-algorithm-ecdsa": "self.version",
- "web-token/jwt-signature-algorithm-eddsa": "self.version",
- "web-token/jwt-signature-algorithm-experimental": "self.version",
- "web-token/jwt-signature-algorithm-hmac": "self.version",
- "web-token/jwt-signature-algorithm-none": "self.version",
- "web-token/jwt-signature-algorithm-rsa": "self.version",
- "web-token/jwt-util-ecc": "self.version",
- "web-token/signature-pack": "self.version"
- },
- "require-dev": {
- "bjeavons/zxcvbn-php": "^1.0",
- "blackfire/php-sdk": "^1.14",
- "ext-curl": "*",
- "ext-gmp": "*",
- "friendsofphp/php-cs-fixer": "^2.16",
- "infection/infection": "^0.15|^0.16|^0.17|^0.18|^0.19|^0.20",
- "matthiasnoback/symfony-config-test": "^3.1|^4.0",
- "nyholm/psr7": "^1.3",
- "php-coveralls/php-coveralls": "^2.0",
- "php-http/mock-client": "^1.0",
- "phpstan/phpstan": "^0.12",
- "phpstan/phpstan-deprecation-rules": "^0.12",
- "phpstan/phpstan-phpunit": "^0.12",
- "phpstan/phpstan-strict-rules": "^0.12",
- "phpunit/phpunit": "^8.0|^9.0",
- "symfony/browser-kit": "^4.2|^5.0",
- "symfony/finder": "^4.2|^5.0",
- "symfony/framework-bundle": "^4.2|^5.0",
- "symfony/http-client": "^5.2",
- "symfony/phpunit-bridge": "^4.2|^5.0",
- "symfony/serializer": "^4.2|^5.0",
- "symfony/var-dumper": "^4.2|^5.0"
- },
- "suggest": {
- "bjeavons/zxcvbn-php": "Adds key quality check for oct keys.",
- "ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
- "php-http/httplug": "To enable JKU/X5U support.",
- "php-http/httplug-bundle": "To enable JKU/X5U support.",
- "php-http/message-factory": "To enable JKU/X5U support.",
- "symfony/serializer": "Use the Symfony serializer to serialize/unserialize JWS and JWE tokens.",
- "symfony/var-dumper": "Used to show data on the debug toolbar."
- },
- "type": "symfony-bundle",
- "autoload": {
- "psr-4": {
- "Jose\\": "src/",
- "Jose\\Component\\Core\\Util\\Ecc\\": [
- "src/Ecc"
- ],
- "Jose\\Component\\Signature\\Algorithm\\": [
- "src/SignatureAlgorithm/ECDSA",
- "src/SignatureAlgorithm/EdDSA",
- "src/SignatureAlgorithm/HMAC",
- "src/SignatureAlgorithm/None",
- "src/SignatureAlgorithm/RSA",
- "src/SignatureAlgorithm/Experimental"
- ],
- "Jose\\Component\\Encryption\\Algorithm\\": [
- "src/EncryptionAlgorithm/Experimental"
- ],
- "Jose\\Component\\Encryption\\Algorithm\\KeyEncryption\\": [
- "src/EncryptionAlgorithm/KeyEncryption/AESGCMKW",
- "src/EncryptionAlgorithm/KeyEncryption/AESKW",
- "src/EncryptionAlgorithm/KeyEncryption/Direct",
- "src/EncryptionAlgorithm/KeyEncryption/ECDHES",
- "src/EncryptionAlgorithm/KeyEncryption/PBES2",
- "src/EncryptionAlgorithm/KeyEncryption/RSA"
- ],
- "Jose\\Component\\Encryption\\Algorithm\\ContentEncryption\\": [
- "src/EncryptionAlgorithm/ContentEncryption/AESGCM",
- "src/EncryptionAlgorithm/ContentEncryption/AESCBC"
- ]
- }
- },
- "notification-url": "https://packagist.org/downloads/",
- "license": [
- "MIT"
- ],
- "authors": [
- {
- "name": "Florent Morselli",
- "homepage": "https://github.com/Spomky"
- },
- {
- "name": "All contributors",
- "homepage": "https://github.com/web-token/jwt-framework/contributors"
- }
- ],
- "description": "JSON Object Signing and Encryption library for PHP and Symfony Bundle.",
- "homepage": "https://github.com/web-token/jwt-framework",
- "keywords": [
- "JOSE",
- "JWE",
- "JWK",
- "JWKSet",
- "JWS",
- "Jot",
- "RFC7515",
- "RFC7516",
- "RFC7517",
- "RFC7518",
- "RFC7519",
- "RFC7520",
- "bundle",
- "jwa",
- "jwt",
- "symfony"
- ],
- "support": {
- "issues": "https://github.com/web-token/jwt-framework/issues",
- "source": "https://github.com/web-token/jwt-framework/tree/v2.2.11"
- },
- "funding": [
- {
- "url": "https://github.com/Spomky",
- "type": "github"
- }
- ],
- "time": "2021-06-25T15:59:52+00:00"
}
],
"packages-dev": [
@@ -3265,16 +1203,16 @@
},
{
"name": "myclabs/deep-copy",
- "version": "1.12.0",
+ "version": "1.12.1",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c"
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
- "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c",
+ "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
+ "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": ""
},
"require": {
@@ -3313,7 +1251,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
- "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0"
+ "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
},
"funding": [
{
@@ -3321,20 +1259,20 @@
"type": "tidelift"
}
],
- "time": "2024-06-12T14:39:25+00:00"
+ "time": "2024-11-08T17:47:46+00:00"
},
{
"name": "nikic/php-parser",
- "version": "v5.2.0",
+ "version": "v5.4.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
- "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb"
+ "reference": "447a020a1f875a434d62f2a401f53b82a396e494"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb",
- "reference": "23c79fbbfb725fb92af9bcf41065c8e9a0d49ddb",
+ "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494",
+ "reference": "447a020a1f875a434d62f2a401f53b82a396e494",
"shasum": ""
},
"require": {
@@ -3377,9 +1315,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
- "source": "https://github.com/nikic/PHP-Parser/tree/v5.2.0"
+ "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0"
},
- "time": "2024-09-15T16:40:33+00:00"
+ "time": "2024-12-30T11:07:19+00:00"
},
{
"name": "phar-io/manifest",
@@ -3820,16 +1758,16 @@
},
{
"name": "phpunit/phpunit",
- "version": "9.6.21",
+ "version": "9.6.22",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
- "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa"
+ "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
- "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa",
+ "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
+ "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
"shasum": ""
},
"require": {
@@ -3840,7 +1778,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
- "myclabs/deep-copy": "^1.12.0",
+ "myclabs/deep-copy": "^1.12.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=7.3",
@@ -3903,7 +1841,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
- "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21"
+ "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
},
"funding": [
{
@@ -3919,7 +1857,7 @@
"type": "tidelift"
}
],
- "time": "2024-09-19T10:50:18+00:00"
+ "time": "2024-12-05T13:48:26+00:00"
},
{
"name": "sebastian/cli-parser",
@@ -4886,16 +2824,16 @@
},
{
"name": "squizlabs/php_codesniffer",
- "version": "3.10.3",
+ "version": "3.11.2",
"source": {
"type": "git",
"url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git",
- "reference": "62d32998e820bddc40f99f8251958aed187a5c9c"
+ "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/62d32998e820bddc40f99f8251958aed187a5c9c",
- "reference": "62d32998e820bddc40f99f8251958aed187a5c9c",
+ "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/1368f4a58c3c52114b86b1abe8f4098869cb0079",
+ "reference": "1368f4a58c3c52114b86b1abe8f4098869cb0079",
"shasum": ""
},
"require": {
@@ -4962,7 +2900,7 @@
"type": "open_collective"
}
],
- "time": "2024-09-18T10:38:58+00:00"
+ "time": "2024-12-11T16:04:26+00:00"
},
{
"name": "theseer/tokenizer",
@@ -5021,12 +2959,6 @@
"version": "7.9.2.0",
"alias": "7.9.3",
"alias_normalized": "7.9.3.0"
- },
- {
- "package": "web-token/jwt-framework",
- "version": "2.2.11.0",
- "alias": "2.3.0",
- "alias_normalized": "2.3.0.0"
}
],
"minimum-stability": "stable",
diff --git a/phpunit.xml b/phpunit.xml
new file mode 100644
index 0000000..6520de3
--- /dev/null
+++ b/phpunit.xml
@@ -0,0 +1,8 @@
+
+
+
+
+ src/tests/DescopeSDKTest.php
+
+
+
\ No newline at end of file
diff --git a/sample/dashboard.php b/sample/dashboard.php
index 527189e..f412ecb 100644
--- a/sample/dashboard.php
+++ b/sample/dashboard.php
@@ -1,5 +1,6 @@
client = new Client();
$this->projectId = $config['projectId'];
$this->managementKey = $config['managementKey'] ?? '';
+ if ($cache) {
+ $this->cache = $cache;
+ } elseif (extension_loaded('apcu') && ini_get('apc.enable_cli')) {
+ $this->cache = new APCuCache();
+ } else {
+ $this->cache = new NullCache();
+ error_log('APCu is not enabled. Falling back to NullCache. Caching is disabled.');
+ }
+
EndpointsV2::setBaseUrl($config['projectId']);
+ }
+
+ /**
+ * Gets the current JWKSet. Fetches a new one if not cached or if explicitly requested.
+ */
+ public function getJWKSets(bool $forceRefresh = false): array
+ {
+ if (!$forceRefresh) {
+ $cachedJWKSets = $this->cache->get(self::JWKS_CACHE_KEY);
+ if ($cachedJWKSets) {
+ return $cachedJWKSets;
+ }
+ }
- $this->jwkSets = $this->getJWKSets();
+ $jwks = $this->fetchJWKSets();
+ $this->cache->set(self::JWKS_CACHE_KEY, $jwks, 3600); // Cache for 1 hour
+ return $jwks;
}
/**
- * Gets the current JWK KeySet that will be needed to validate the JWT
+ * Fetch the JWK KeySet from the Descope API.
*/
- private function getJWKSets()
+ private function fetchJWKSets(): array
{
try {
$url = EndpointsV2::getPublicKeyPath() . '/' . $this->projectId;
-
- // Fetch JWK public key from Descope API
- $res = $this->client->request('GET', $url);
- $jwkSets = json_decode($res->getBody(), true);
+ $response = $this->client->request('GET', $url);
+ $jwkSets = json_decode($response->getBody(), true);
+
+ if (!isset($jwkSets['keys']) || !is_array($jwkSets['keys'])) {
+ throw new \Exception('Invalid JWK response');
+ }
+
return $jwkSets;
- } catch (RequestException $re) {
- return $re;
+ } catch (RequestException $e) {
+ throw new \Exception('Failed to fetch JWK KeySet: ' . $e->getMessage());
}
}
}
diff --git a/src/SDK/DescopeSDK.php b/src/SDK/DescopeSDK.php
index 67ac5a2..554ab77 100644
--- a/src/SDK/DescopeSDK.php
+++ b/src/SDK/DescopeSDK.php
@@ -12,6 +12,10 @@
use Descope\SDK\Auth\Management\User;
use Descope\SDK\Auth\Management\Audit;
use Descope\SDK\EndpointsV1;
+use Descope\SDK\EndpointsV2;
+use Descope\SDK\Exception\AuthException;
+use Descope\SDK\Exception\ValidationException;
+
use Descope\SDK\Management\MgmtV1;
class DescopeSDK
@@ -45,6 +49,8 @@ public function __construct(array $config)
MgmtV1::setBaseUrl($config['projectId']);
}
+ $this->verifier = new Verifier($this->config, $this->api);
+
$this->password = new Password($this->api);
$this->sso = new SSO($this->api);
}
@@ -56,16 +62,16 @@ public function __construct(array $config)
* @return bool Verification result.
* @throws AuthException
*/
- public function verify($sessionToken = null)
+ public function verify($sessionToken = null): bool
{
- $sessionToken = $sessionToken ?? $_COOKIE[EndpointsV1::SESSION_COOKIE_NAME_NAME] ?? null;
+ $sessionToken = $sessionToken ?? $_COOKIE[EndpointsV1::$SESSION_COOKIE_NAME] ?? null;
if (!$sessionToken) {
- throw new \InvalidArgumentException('Session token is required.');
+ throw ValidationException::forMissingSessionToken();
}
- $verifier = new Verifier($this->config);
- return $verifier->verify($sessionToken);
+ $verifier = new Verifier($this->config, $this->api);
+ return $this->verifier->verify($sessionToken);
}
/**
@@ -75,16 +81,26 @@ public function verify($sessionToken = null)
* @return array The new session information.
* @throws AuthException
*/
- public function refreshSession($refreshToken = null)
+ public function refreshSession($refreshToken = null): array
{
- $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::REFRESH_COOKIE_NAME] ?? null;
+ $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::$REFRESH_COOKIE_NAME] ?? null;
- if (!$refreshToken) {
- throw new \InvalidArgumentException('Refresh token is required.');
+ if (empty($refreshToken)) {
+ throw ValidationException::forMissingRefreshToken();
}
- $verifier = new Verifier($this->config);
- return $verifier->refreshSession($refreshToken);
+ try {
+ return $this->api->doPost(
+ EndpointsV1::$REFRESH_TOKEN_PATH,
+ [],
+ false,
+ $refreshToken
+ );
+ } catch (RequestException $e) {
+ $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 'N/A';
+ $responseBody = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : 'No response body';
+ throw new AuthException($statusCode, 'RequestException', $e->getMessage());
+ }
}
/**
@@ -95,17 +111,21 @@ public function refreshSession($refreshToken = null)
* @return array The refreshed session information.
* @throws AuthException
*/
- public function verifyAndRefreshSession($sessionToken = null, $refreshToken = null)
+ public function verifyAndRefreshSession($sessionToken = null, $refreshToken = null): array
{
- $sessionToken = $sessionToken ?? $_COOKIE[EndpointsV1::SESSION_COOKIE_NAME] ?? null;
- $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::REFRESH_COOKIE_NAME] ?? null;
+ $sessionToken = $sessionToken ?? $_COOKIE[EndpointsV1::$SESSION_COOKIE_NAME] ?? null;
+ $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::$REFRESH_COOKIE_NAME] ?? null;
- if (!$sessionToken || !$refreshToken) {
- throw new \InvalidArgumentException('Session token and refresh token are required.');
+ if (empty($sessionToken) || empty($refreshToken)) {
+ throw new ValidateException('Session or refresh token cannot be null or empty.');
+ }
+
+ try {
+ $this->verify($sessionToken);
+ return $this->refreshSession($refreshToken);
+ } catch (AuthException $e) {
+ return $this->refreshSession($refreshToken);
}
-
- $verifier = new Verifier($this->config);
- return $verifier->verifyAndRefreshSession($sessionToken, $refreshToken);
}
/**
@@ -115,12 +135,12 @@ public function verifyAndRefreshSession($sessionToken = null, $refreshToken = nu
* @return array The JWT claims.
* @throws AuthException
*/
- public function getClaims($token = null)
+ public function getClaims($token = null): array
{
- $token = $token ?? $_COOKIE[EndpointsV1::SESSION_COOKIE_NAME] ?? null;
+ $token = $token ?? $_COOKIE[EndpointsV1::$SESSION_COOKIE_NAME] ?? null;
if (!$token) {
- throw new \InvalidArgumentException('Token is required.');
+ throw ValidationException::forMissingSessionToken();
}
$extractor = new Extractor($this->config);
@@ -134,19 +154,25 @@ public function getClaims($token = null)
* @return array The user details.
* @throws AuthException
*/
- public function getUserDetails(string $refreshToken = null)
+ public function getUserDetails(string $refreshToken = null): array
{
- $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::REFRESH_COOKIE_NAME] ?? null;
+ $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::$REFRESH_COOKIE_NAME] ?? null;
if (!$refreshToken) {
- throw new \InvalidArgumentException('Refresh token is required.');
+ throw ValidationException::forMissingRefreshToken();
}
- return $this->api->doGet(
- EndpointsV1::$ME_PATH,
- false,
- $refreshToken
- );
+ try {
+ return $this->api->doGet(
+ EndpointsV1::$ME_PATH,
+ false,
+ $refreshToken
+ );
+ } catch (RequestException $e) {
+ $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 'N/A';
+ $responseBody = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : 'No response body';
+ throw new AuthException($statusCode, 'RequestException', $e->getMessage());
+ }
}
/**
@@ -158,18 +184,25 @@ public function getUserDetails(string $refreshToken = null)
*/
public function logout(string $refreshToken = null): void
{
- $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::REFRESH_COOKIE_NAME] ?? null;
+ $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::$REFRESH_COOKIE_NAME] ?? null;
if (!$refreshToken) {
- throw new \InvalidArgumentException('Refresh token is required.');
+ throw ValidationException::forMissingRefreshToken();
}
- $this->api->doPost(
- EndpointsV1::$LOGOUT_PATH,
- [],
- false,
- $refreshToken
- );
+ try {
+ $this->api->doPost(
+ EndpointsV1::$LOGOUT_PATH,
+ [],
+ false,
+ $refreshToken
+ );
+ return;
+ } catch (RequestException $e) {
+ $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 'N/A';
+ $responseBody = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : 'No response body';
+ throw new AuthException($statusCode, 'RequestException', $e->getMessage());
+ }
}
/**
@@ -181,18 +214,25 @@ public function logout(string $refreshToken = null): void
*/
public function logoutAll(string $refreshToken = null): void
{
- $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::REFRESH_COOKIE_NAME] ?? null;
+ $refreshToken = $refreshToken ?? $_COOKIE[EndpointsV1::$REFRESH_COOKIE_NAME] ?? null;
if (!$refreshToken) {
- throw new \InvalidArgumentException('Refresh token is required.');
+ throw ValidationException::forMissingRefreshToken();
}
- $this->api->doPost(
- EndpointsV1::LOGOUT_ALL_PATH,
- [],
- false,
- $refreshToken
- );
+ try {
+ $this->api->doPost(
+ EndpointsV1::$LOGOUT_ALL_PATH,
+ [],
+ false,
+ $refreshToken
+ );
+ return;
+ } catch (RequestException $e) {
+ $statusCode = $e->getResponse() ? $e->getResponse()->getStatusCode() : 'N/A';
+ $responseBody = $e->getResponse() ? $e->getResponse()->getBody()->getContents() : 'No response body';
+ throw new AuthException($statusCode, 'RequestException', $e->getMessage());
+ }
}
/**
diff --git a/src/SDK/Exception/ValidationException.php b/src/SDK/Exception/ValidationException.php
new file mode 100644
index 0000000..c9ec9a4
--- /dev/null
+++ b/src/SDK/Exception/ValidationException.php
@@ -0,0 +1,57 @@
+hash = $hash;
+ }
+
+ /**
+ * Convert object data to an array format.
+ *
+ * @return array The password data as an associative array.
+ */
+ public function toArray(): array
+ {
+ return [
+ 'md5' => [
+ 'hash' => $this->hash,
+ ],
+ ];
+ }
+}
diff --git a/src/SDK/Management/Password/UserPasswordPHPass.php b/src/SDK/Management/Password/UserPasswordPHPass.php
index 33a4257..ceb1098 100644
--- a/src/SDK/Management/Password/UserPasswordPHPass.php
+++ b/src/SDK/Management/Password/UserPasswordPHPass.php
@@ -49,4 +49,4 @@ public function toArray(): array
],
];
}
-}
\ No newline at end of file
+}
diff --git a/src/SDK/Management/Password/UserPasswordPbkdf2.php b/src/SDK/Management/Password/UserPasswordPbkdf2.php
index 1de37dd..cec8bbb 100644
--- a/src/SDK/Management/Password/UserPasswordPbkdf2.php
+++ b/src/SDK/Management/Password/UserPasswordPbkdf2.php
@@ -53,4 +53,4 @@ public function toArray(): array
],
];
}
-}
\ No newline at end of file
+}
diff --git a/src/SDK/Management/Role.php b/src/SDK/Management/Role.php
new file mode 100644
index 0000000..5e822be
--- /dev/null
+++ b/src/SDK/Management/Role.php
@@ -0,0 +1,96 @@
+api = $api;
+ }
+
+ /**
+ * Validates tenant permissions for a JWT response.
+ *
+ * @param array $jwtResponse JWT response data.
+ * @param string $tenant Tenant ID.
+ * @param array $permissions Permissions to validate.
+ * @return bool True if tenant permissions are valid, false otherwise.
+ * @throws AuthException If JWT response is invalid.
+ */
+ public function validateTenantPermissions(array $jwtResponse, array $permissions, ?string $tenant = null): bool
+ {
+ $tenant = $tenant ?? '';
+
+ if (!is_array($permissions)) {
+ $permissions = [$permissions];
+ }
+
+ if (!is_array($jwtResponse)) {
+ throw new AuthException(400, 'Invalid JWT response hash');
+ }
+
+ $grantedPermissions = $jwtResponse['permissions'] ?? [];
+ if (!empty($tenant)) {
+ if (empty($jwtResponse['tenants'][$tenant])) {
+ return false;
+ }
+ $grantedPermissions = $jwtResponse['tenants'][$tenant]['permissions'] ?? [];
+ }
+
+ return empty(array_diff($permissions, $grantedPermissions));
+ }
+
+ /**
+ * Validates roles for a JWT response.
+ *
+ * @param array $jwtResponse JWT response data.
+ * @param array $roles Roles to validate.
+ * @return bool True if roles are valid, false otherwise.
+ */
+ public function validateRoles(array $jwtResponse, array $roles): bool
+ {
+ return $this->validateTenantRoles($jwtResponse, '', $roles);
+ }
+
+ /**
+ * Validates tenant roles for a JWT response.
+ *
+ * @param array $jwtResponse JWT response data.
+ * @param string $tenant Tenant ID.
+ * @param array $roles Roles to validate.
+ * @return bool True if tenant roles are valid, false otherwise.
+ * @throws AuthException If JWT response is invalid.
+ */
+ public function validateTenantRoles(array $jwtResponse, string $tenant, array $roles): bool
+ {
+ if (!is_array($roles)) {
+ $roles = [$roles];
+ }
+
+ if (!is_array($jwtResponse)) {
+ throw new AuthException(400, 'Invalid JWT response hash');
+ }
+
+ $grantedRoles = $jwtResponse['roles'] ?? [];
+ if (!empty($tenant)) {
+ if (empty($jwtResponse['tenants'][$tenant])) {
+ return false;
+ }
+ $grantedRoles = $jwtResponse['tenants'][$tenant]['roles'] ?? [];
+ }
+
+ return empty(array_diff($roles, $grantedRoles));
+ }
+}
diff --git a/src/SDK/Token/Extractor.php b/src/SDK/Token/Extractor.php
index fcee856..4374f7d 100644
--- a/src/SDK/Token/Extractor.php
+++ b/src/SDK/Token/Extractor.php
@@ -5,13 +5,6 @@
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Psr7\Request;
-use Jose\Component\Core\Util\JsonConverter;
-use Jose\Component\Core\AlgorithmManager;
-use Jose\Component\Core\JWKSet;
-use Jose\Component\Signature\Algorithm\RS256;
-use Jose\Component\Signature\JWSVerifier;
-use Jose\Component\Signature\Serializer\CompactSerializer;
-use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Descope\SDK\Exception\TokenException;
use Descope\SDK\Configuration\SDKConfig;
@@ -32,68 +25,201 @@ public function __construct($config)
/**
* Return an array representing the Token's claims.
*
- * @return array|int|string>
+ * @return array
*/
- public function getClaims($sessionToken): array
+ public function getClaims(string $sessionToken): array
{
- $jws = $this->parseToken($sessionToken);
- return json_decode($jws->getPayload(), true) ?? [];
+ $parts = $this->parseToken($sessionToken);
+ return $parts['payload'] ?? [];
}
/**
- * Return all user information using /auth/me API endpoint.
+ * Parse and validate the JWT token.
*
- * @return json
+ * @throws TokenException if validation fails.
*/
- public function getUserDetails($refreshToken)
+ public function parseToken(string $sessionToken): array
{
- $client = $this->config->client;
- $url = EndpointsV1::$ME_PATH;
- $header = 'Bearer ' . $this->config->projectId . ":" . $refreshToken;
-
- try {
- $response = $client->get($url, ['headers' => ['Authorization' => $header]]);
- return json_decode($response->getBody(), true);
- } catch (RequestException $e) {
- throw new TokenException('Failed to retrieve user details: ' . $e->getMessage());
+ $parts = explode('.', $sessionToken);
+ if (count($parts) !== 3) {
+ throw new TokenException('Invalid JWT format');
}
+
+ $header = $this->decodeJWTPart($parts[0]);
+ $payload = $this->decodeJWTPart($parts[1]);
+ $signature = $this->base64UrlDecode($parts[2]);
+
+ if (!isset($header['alg']) || $header['alg'] !== 'RS256') {
+ throw new TokenException('Unsupported algorithm. Only RS256 is supported.');
+ }
+
+ return [
+ 'raw' => [
+ 'header' => $parts[0],
+ 'payload' => $parts[1],
+ 'signature' => $parts[2]
+ ],
+ 'header' => $header,
+ 'payload' => $payload,
+ 'signature' => $signature
+ ];
}
/**
- * Parse a JWT string, returning the JWS Object with all of the claims if valid signature.
- *
- * @throws TokenException if signature verification fails or parsing fails.
+ * Validate a JWT using the provided JWK Set.
*/
- public function parseToken($sessionToken)
+ public function validateJWT(string $sessionToken): array
{
- try {
- $jwkSets = $this->config->jwkSets;
- $jwkSet = JWKSet::createFromKeyData($jwkSets);
-
- $jwsVerifier = new JWSVerifier(
- new AlgorithmManager(
- [
- new RS256(),
- ]
- )
- );
+ $useRefreshedKey = false;
+ do {
+ try {
+ $jwkSet = $this->config->getJWKSets($useRefreshedKey);
+ $jwt = $this->parseToken($sessionToken);
- $serializerManager = new JWSSerializerManager(
- [
- new CompactSerializer(),
- ]
- );
-
- $jws = $serializerManager->unserialize($sessionToken);
-
- $isVerified = $jwsVerifier->verifyWithKeySet($jws, $jwkSet, 0);
- if ($isVerified) {
- return $jws;
- } else {
- throw new TokenException(TokenException::MSG_SIGNATURE_INVALID);
+ if (!isset($jwt['header']['kid'])) {
+ throw new TokenException('Missing key ID in JWT header');
+ }
+
+ $matchingKey = null;
+ foreach ($jwkSet['keys'] as $key) {
+ if ($key['kid'] === $jwt['header']['kid']) {
+ $matchingKey = $key;
+ break;
+ }
+ }
+
+ if (!$matchingKey) {
+ throw new TokenException('No matching key found in JWKS');
+ }
+
+ $publicKeyPEM = $this->convertJWKToPEM($matchingKey);
+ $signatureValid = $this->verifySignature(
+ $jwt['raw']['header'] . '.' . $jwt['raw']['payload'],
+ $jwt['signature'],
+ $publicKeyPEM
+ );
+
+ if (!$signatureValid) {
+ throw new TokenException('Invalid signature');
+ }
+
+ return $jwt['payload'];
+ } catch (TokenException $e) {
+ if ($useRefreshedKey) {
+ throw new TokenException('JWT validation failed after retry: ' . $e->getMessage());
+ }
+ $useRefreshedKey = true;
}
- } catch (Exception $e) {
- throw new TokenException(TokenException::MSG_COULD_NOT_PARSE);
+ } while ($useRefreshedKey);
+
+ throw new TokenException('JWT validation failed');
+ }
+
+ /**
+ * Verify JWT signature.
+ */
+ private function verifySignature(string $signedData, string $signature, string $publicKeyPEM): bool
+ {
+ $publicKey = openssl_pkey_get_public($publicKeyPEM);
+ if (!$publicKey) {
+ throw new TokenException('Invalid public key');
+ }
+
+ $result = openssl_verify(
+ $signedData,
+ $signature,
+ $publicKey,
+ OPENSSL_ALGO_SHA256
+ );
+
+ return $result === 1;
+ }
+
+ /**
+ * Convert JWK to PEM format.
+ */
+ private function convertJWKToPEM(array $jwk): string
+ {
+ if (!isset($jwk['kty']) || $jwk['kty'] !== 'RSA') {
+ throw new TokenException('Invalid key type. Only RSA is supported.');
+ }
+
+ $modulus = $this->base64UrlDecode($jwk['n']);
+ $exponent = $this->base64UrlDecode($jwk['e']);
+
+ // Remove leading null bytes from modulus
+ $modulus = ltrim($modulus, "\x00");
+
+ // Construct RSA public key in ASN.1 format
+ $modulus = pack('Ca*a*', 0x02, $this->encodeLength(strlen($modulus)), $modulus);
+ $exponent = pack('Ca*a*', 0x02, $this->encodeLength(strlen($exponent)), $exponent);
+
+ $rsaPublicKey = pack('Ca*a*', 0x30, $this->encodeLength(strlen($modulus . $exponent)), $modulus . $exponent);
+
+ // Add RSA public key algorithm identifier
+ $algorithmIdentifier = pack('H*', '300d06092a864886f70d0101010500');
+ $bitString = pack('Ca*', 0x03, $this->encodeLength(strlen($rsaPublicKey) + 1) . "\x00" . $rsaPublicKey);
+
+ $der = pack(
+ 'Ca*a*',
+ 0x30,
+ $this->encodeLength(strlen($algorithmIdentifier . $bitString)),
+ $algorithmIdentifier . $bitString
+ );
+
+ return sprintf(
+ "-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n",
+ chunk_split(base64_encode($der), 64, "\n")
+ );
+ }
+
+
+ /**
+ * Helper to encode the length in DER format.
+ */
+ private function encodeLength(int $length): string
+ {
+ if ($length < 128) {
+ return chr($length);
+ }
+
+ $temp = $length;
+ $bytes = '';
+ while ($temp > 0) {
+ $bytes = chr($temp & 0xFF) . $bytes;
+ $temp >>= 8;
+ }
+ return chr(0x80 | strlen($bytes)) . $bytes;
+ }
+
+ /**
+ * Decodes a Base64Url-encoded string.
+ */
+ private function base64UrlDecode(string $data): string
+ {
+ $padded = str_pad(
+ strtr($data, '-_', '+/'),
+ strlen($data) + (4 - strlen($data) % 4) % 4,
+ '='
+ );
+
+ $decoded = base64_decode($padded, true);
+ if ($decoded === false) {
+ throw new TokenException('Invalid base64url encoding');
+ }
+
+ return $decoded;
+ }
+
+ private function decodeJWTPart(string $data): array
+ {
+ $decoded = $this->base64UrlDecode($data);
+ $result = json_decode($decoded, true);
+
+ if (JSON_ERROR_NONE !== json_last_error()) {
+ throw new TokenException('Invalid JWT part encoding');
}
+
+ return $result;
}
}
diff --git a/src/SDK/Token/Verifier.php b/src/SDK/Token/Verifier.php
index addc1e8..bafb996 100644
--- a/src/SDK/Token/Verifier.php
+++ b/src/SDK/Token/Verifier.php
@@ -4,30 +4,28 @@
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
+use Descope\SDK\Exception\TokenException;
use GuzzleHttp\Psr7\Request;
-use Jose\Component\Core\Util\JsonConverter;
-use Jose\Component\Core\AlgorithmManager;
-use Jose\Component\Core\JWKSet;
-use Jose\Component\Signature\Algorithm\RS256;
-use Jose\Component\Signature\JWSVerifier;
-use Jose\Component\Signature\Serializer\CompactSerializer;
-use Jose\Component\Signature\Serializer\JWSSerializerManager;
use Descope\SDK\Token\Extractor;
use Descope\SDK\Configuration\SDKConfig;
use Descope\SDK\EndpointsV1;
+use Descope\SDK\API;
final class Verifier
{
private SDKConfig $config;
+ private API $api;
/**
* Constructor for Verifier class.
*
* @param SDKConfig $config Base configuration options for the SDK.
*/
- public function __construct($config)
+ public function __construct(SDKConfig $config, API $api)
{
$this->config = $config;
+ $this->api = $api;
+ $this->extractor = new Extractor($this->config);
}
/**
@@ -37,149 +35,44 @@ public function __construct($config)
* @return boolean Token signature is valid and not expired.
* @throws AuthException If the refresh operation fails.
*/
- public function verify($sessionToken, ?string $audience = null)
+ public function verify(string $sessionToken, ?string $audience = null): bool
{
try {
- $extractor = new Extractor($this->config);
- $jws = $extractor->parseToken($sessionToken);
-
- // If JWT signature is valid
- if (isset($jws)) {
- $payload = json_decode($jws->getPayload());
+ // First validate the token signature
+ $validatedToken = $this->extractor->validateJWT($sessionToken);
+ if (!$validatedToken) {
+ throw new TokenException('Invalid token signature');
+ }
+
+ // Verify expiration
+ if (isset($validatedToken['exp']) && time() > $validatedToken['exp']) {
+ throw new TokenException('Token has expired');
+ }
- // Check to make sure JWT is not expired
- if (isset($payload->exp) && time() < $payload->exp) {
- if ($audience && (!isset($payload->aud) || $payload->aud !== $audience)) {
- return false;
+ // Verify audience if provided
+ if ($audience !== null) {
+ if (!isset($validatedToken['aud'])) {
+ throw new TokenException('Token is missing audience claim');
+ }
+
+ // Handle both string and array audience claims
+ $tokenAudience = $validatedToken['aud'];
+ if (is_array($tokenAudience)) {
+ if (!in_array($audience, $tokenAudience, true)) {
+ throw new TokenException('Token audience does not match expected value');
+ }
+ } else {
+ if ($tokenAudience !== $audience) {
+ throw new TokenException('Token audience does not match expected value');
}
- return true;
}
}
- return false;
- } catch (TokenException $te) {
- throw TokenException::MSG_SIGNATURE_INVALID;
- }
- }
-
- /**
- * Refreshes the session token, with the provided refresh token.
- *
- * @param string $refreshToken The refresh token.
- * @return array The refreshed JWT response.
- * @throws AuthException If the refresh operation fails.
- */
- public function refreshSession(string $refreshToken): array
- {
- $this->validateRefreshTokenNotNil($refreshToken);
- $this->validateToken($refreshToken);
- $uri = EndpointsV1::$REFRESH_TOKEN_PATH;
- $response = $this->doPost($uri, [], $refreshToken);
- return $this->generateJwtResponse($response, $refreshToken);
- }
-
- /**
- * Verifies the session token, and automatically refreshes when expired.
- *
- * @param string $sessionToken The session token.
- * @param string $refreshToken The refresh token.
- * @return array The JWT response.
- * @throws AuthException If both tokens are missing or verification fails.
- */
- public function verifyAndRefreshSession(string $sessionToken, string $refreshToken): array
- {
- if (empty($sessionToken)) {
- throw new AuthException(400, 'Session token is missing');
- }
-
- try {
- $this->validateToken($sessionToken);
- return $this->generateJwtResponse($sessionToken, $refreshToken);
- } catch (AuthException $e) {
- return $this->refreshSession($refreshToken);
- }
- }
-
- /**
- * Validates permissions for a JWT response.
- *
- * @param array $jwtResponse JWT response data.
- * @param array $permissions Permissions to validate.
- * @return bool True if permissions are valid, false otherwise.
- */
- public function validatePermissions(array $jwtResponse, array $permissions): bool
- {
- return $this->validateTenantPermissions($jwtResponse, '', $permissions);
- }
-
- /**
- * Validates tenant permissions for a JWT response.
- *
- * @param array $jwtResponse JWT response data.
- * @param string $tenant Tenant ID.
- * @param array $permissions Permissions to validate.
- * @return bool True if tenant permissions are valid, false otherwise.
- * @throws AuthException If JWT response is invalid.
- */
- public function validateTenantPermissions(array $jwtResponse, string $tenant, array $permissions): bool
- {
- if (!is_array($permissions)) {
- $permissions = [$permissions];
- }
-
- if (!is_array($jwtResponse)) {
- throw new AuthException(400, 'Invalid JWT response hash');
- }
-
- $grantedPermissions = $jwtResponse['permissions'] ?? [];
- if (!empty($tenant)) {
- if (empty($jwtResponse['tenants'][$tenant])) {
- return false;
- }
- $grantedPermissions = $jwtResponse['tenants'][$tenant]['permissions'] ?? [];
- }
-
- return empty(array_diff($permissions, $grantedPermissions));
- }
-
- /**
- * Validates roles for a JWT response.
- *
- * @param array $jwtResponse JWT response data.
- * @param array $roles Roles to validate.
- * @return bool True if roles are valid, false otherwise.
- */
- public function validateRoles(array $jwtResponse, array $roles): bool
- {
- return $this->validateTenantRoles($jwtResponse, '', $roles);
- }
- /**
- * Validates tenant roles for a JWT response.
- *
- * @param array $jwtResponse JWT response data.
- * @param string $tenant Tenant ID.
- * @param array $roles Roles to validate.
- * @return bool True if tenant roles are valid, false otherwise.
- * @throws AuthException If JWT response is invalid.
- */
- public function validateTenantRoles(array $jwtResponse, string $tenant, array $roles): bool
- {
- if (!is_array($roles)) {
- $roles = [$roles];
- }
-
- if (!is_array($jwtResponse)) {
- throw new AuthException(400, 'Invalid JWT response hash');
+ // All validations passed
+ return true;
+ } catch (TokenException $e) {
+ // You might want to throw a specific error or return false depending on your needs
+ throw new TokenException('Token validation failed: ' . $e->getMessage());
}
-
- $grantedRoles = $jwtResponse['roles'] ?? [];
- if (!empty($tenant)) {
- if (empty($jwtResponse['tenants'][$tenant])) {
- return false;
- }
- $grantedRoles = $jwtResponse['tenants'][$tenant]['roles'] ?? [];
- }
-
- return empty(array_diff($roles, $grantedRoles));
}
}
diff --git a/src/tests/DescopeSDKTest.php b/src/tests/DescopeSDKTest.php
index 3325b50..9b8d7c7 100644
--- a/src/tests/DescopeSDKTest.php
+++ b/src/tests/DescopeSDKTest.php
@@ -4,42 +4,42 @@
use PHPUnit\Framework\TestCase;
use Descope\SDK\DescopeSDK;
+use Descope\SDK\API;
+use Descope\SDK\Auth\Password;
+use Descope\SDK\Auth\SSO;
+use Descope\SDK\Management\Management;
+use Descope\SDK\Exception\ValidationException;
final class DescopeSDKTest extends TestCase
{
- public $descopeSDK;
+ private $config;
+ private $sdk;
- public function setUp(): void
+ protected function setUp(): void
{
- // $descopeSDK = new DescopeSDK(
- // [
- // 'projectId' => "",
- // 'managementKey' => "" // This can be optional
- // ]
- // );
+ $this->config = [
+ 'projectId' => 'test_project_id',
+ 'managementKey' => 'test_management_key'
+ ];
+ $this->sdk = new DescopeSDK($this->config);
}
- public function testVerify(): void
+ public function testConstructorInitializesComponents()
{
- $token = '...';
- // $this->assertTrue($this->descopeSDK->verify($token));
+ $this->assertInstanceOf(Password::class, $this->sdk->password());
+ $this->assertInstanceOf(SSO::class, $this->sdk->sso());
+ $this->assertInstanceOf(Management::class, $this->sdk->management());
}
- public function getClaims(): void
+ public function testVerifyThrowsExceptionWithoutToken()
{
- $token = '...';
- // $this->assertNotEmpty($this->descopeSDK->getClaims($token));
+ $this->expectException(ValidationException::class);
+ $this->sdk->verify(null);
}
- public function testUserDetails(): void
+ public function testRefreshSessionThrowsExceptionWithoutToken()
{
- $refresh_token = '...';
- // $this->assertIsArray($this->descopeSDK->getUser($refresh_token));
- }
-
- public function testPassword(): void
- {
- // $result = $this->descopeSDK->password->signUp("example@descope.com", "Password123!", []);
- // $this->assertIsArray($this->descopeSDK->password->signUp("example@descope.com", "Password123!", []));
+ $this->expectException(ValidationException::class);
+ $this->sdk->refreshSession(null);
}
}
diff --git a/src/tests/Management/UserPwdTest.php b/src/tests/Management/UserPwdTest.php
index ec6eeb6..c5832b9 100644
--- a/src/tests/Management/UserPwdTest.php
+++ b/src/tests/Management/UserPwdTest.php
@@ -8,6 +8,7 @@
use Descope\SDK\Management\Password\UserPasswordFirebase;
use Descope\SDK\Management\Password\UserPasswordPbkdf2;
use Descope\SDK\Management\Password\UserPasswordDjango;
+use Descope\SDK\Management\Password\UserPasswordMD5;
class UserPwdTest extends TestCase
{
@@ -81,6 +82,19 @@ public function testUserPasswordDjango()
$this->assertEquals($expectedArray, $userPasswordDjango->toArray());
}
+ public function testUserPasswordMD5()
+ {
+ $md5Hash = '87f77988ccb5aa917c93201ba314fcd4';
+ $userPasswordMD5 = new UserPasswordMD5($md5Hash);
+ $expectedArray = [
+ 'md5' => [
+ 'hash' => $md5Hash,
+ ],
+ ];
+
+ $this->assertEquals($expectedArray, $userPasswordMD5->toArray());
+ }
+
public function testUserPasswordWithCleartext()
{
$cleartextPassword = 'mypassword';
diff --git a/src/tests/Management/UserTest.php b/src/tests/Management/UserTest.php
index c3eb1eb..5d98fb9 100644
--- a/src/tests/Management/UserTest.php
+++ b/src/tests/Management/UserTest.php
@@ -6,9 +6,6 @@
use Descope\SDK\DescopeSDK;
use Descope\SDK\Management\Password\UserPassword;
use Descope\SDK\Management\Password\UserPasswordBcrypt;
-use Descope\SDK\Management\Password\UserPasswordFirebase;
-use Descope\SDK\Management\Password\UserPasswordPbkdf2;
-use Descope\SDK\Management\Password\UserPasswordDjango;
use Descope\SDK\Management\User;
use Descope\SDK\Management\AssociatedTenant;
use Descope\SDK\Management\UserObj;