diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml deleted file mode 100644 index 4804107..0000000 --- a/.github/workflows/ci.yaml +++ /dev/null @@ -1,67 +0,0 @@ -on: - push: - -name: CI - -jobs: - dependency-validation: - name: Dependency Validation - - runs-on: ubuntu-latest - timeout-minutes: 5 - - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - - - name: Checkout - uses: actions/checkout@v4 - - - name: Cache Composer dependencies - uses: actions/cache@v4 - with: - path: /tmp/composer-cache - key: "${{ runner.os }}-${{ hashFiles('**/composer.lock') }}" - - - name: Install Composer - uses: php-actions/composer@v6 - - - name: Ensure that composer.json is valid - run: composer validate --no-ansi --strict composer.json - - - name: Ensure that dependencies can be installed - run: composer install --no-ansi --dry-run - - - unit-tests: - name: Unit Tests - runs-on: ubuntu-latest - - needs: - - dependency-validation - - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - - - name: Checkout - uses: actions/checkout@v4 - - - name: Cache Composer dependencies - uses: actions/cache@v4 - with: - path: /tmp/composer-cache - key: "${{ runner.os }}-${{ hashFiles('**/composer.lock') }}" - - - name: Install Composer - uses: php-actions/composer@v6 - - - name: Run PHPUnit - run: make test-unit - - - name: Run php-cs-fixer - run: make php-cs-fixer diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..622dfb9 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,24 @@ +on: + push: + branches: + - master + +permissions: + contents: write + pull-requests: write + +name: release-please + +jobs: + release-please: + runs-on: ubuntu-latest + steps: + - uses: googleapis/release-please-action@v4 + with: + # this assumes that you have created a personal access token + # (PAT) and configured it as a GitHub action secret named + # `MY_RELEASE_PLEASE_TOKEN` (this secret name is not important). + token: ${{ secrets.GITHUB_TOKEN }} + # this is a built-in strategy in release-please, see "Action Inputs" + # for more options + release-type: php \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index b20b1a5..0000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,45 +0,0 @@ -on: - push: - branches: - - master - -name: Release - -jobs: - release: - name: Semantic Release - runs-on: ubuntu-latest - steps: - - name: Setup PHP - uses: shivammathur/setup-php@v2 - with: - php-version: '8.3' - - - name: Checkout - uses: actions/checkout@v4 - - - name: Cache Composer dependencies - uses: actions/cache@v4 - with: - path: /tmp/composer-cache - key: "${{ runner.os }}-${{ hashFiles('**/composer.lock') }}" - - - name: Install Composer - uses: php-actions/composer@v6 - - - name: Run PHPUnit - run: php -d xdebug.mode=coverage ./vendor/bin/phpunit - - - name: Make Coverage Badge - uses: action-badges/cobertura-coverage-xml-badges@0.3.0 - with: - file-name: coverage.svg - badge-branch: gh-pages - coverage-file-name: tests/coverage.latest/coverage.xml - github-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Execute Semantic Release - id: semantic - uses: cycjimmy/semantic-release-action@v4 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..2746fe1 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,31 @@ +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + php-tests: + runs-on: ubuntu-latest + + strategy: + matrix: + php: [8.3, 8.4] + os: [ubuntu-latest] + + name: PHP${{ matrix.php }} + + steps: + - name: Checkout code + uses: actions/checkout@v1 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + + - name: Install dependencies + run: composer install --no-interaction + + - name: Execute Lint and Unit Tests + run: make test diff --git a/.gitignore b/.gitignore index 4af6a77..2e6a7e8 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ coverage.xml .php_cs.cache .phpunit.cache .php-cs-fixer.cache +.cache diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php new file mode 100644 index 0000000..4c8a26a --- /dev/null +++ b/.php-cs-fixer.php @@ -0,0 +1,27 @@ + true, + 'array_syntax' => ['syntax' => 'short'], + 'no_unused_imports' => true, + 'single_line_comment_style' => true, + 'single_line_comment_spacing' => true, + 'control_structure_braces' => true, + 'control_structure_continuation_position' => true, + 'no_useless_else' => true, + 'no_superfluous_elseif' => true, + 'simplified_if_return' => true, +]; + +$finder = PhpCsFixer\Finder::create() + ->in($dirs); + +return (new PhpCsFixer\Config()) + ->setRules($rules) + ->setFinder($finder) + ->setCacheFile(__DIR__ . '/.cache/.php-cs-fixer.cache'); diff --git a/.php_cs.php b/.php_cs.php deleted file mode 100644 index 1c16242..0000000 --- a/.php_cs.php +++ /dev/null @@ -1,12 +0,0 @@ -setRiskyAllowed(true) - ->setFinder( - PhpCsFixer\Finder::create() - ->in(__DIR__ . '/src') - ->in(__DIR__ . '/tests') - ) -; diff --git a/.releaserc.json b/.releaserc.json deleted file mode 100644 index 554a96b..0000000 --- a/.releaserc.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "branches": [ - "+([0-9])?(.{+([0-9]),x}).x", - "master" - ], - "plugins": [ - "@semantic-release/commit-analyzer", - "@semantic-release/release-notes-generator", - "@semantic-release/github" - ] -} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..cc2a000 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,28 @@ +# Changelog + +## [2.0.0](https://github.com/compwright/php-jwks/compare/v1.0.0...v2.0.0) (2025-03-20) + + +### ⚠ BREAKING CHANGES + +* initial commit + +### Features + +* initial commit ([8dcd49a](https://github.com/compwright/php-jwks/commit/8dcd49a177f6b9fc517749a85a8dbeaef004cc5f)) + + +### Miscellaneous Chores + +* **master:** release 1.0.0 ([#3](https://github.com/compwright/php-jwks/issues/3)) ([7e086ba](https://github.com/compwright/php-jwks/commit/7e086baba287770a7532e2ec5b0808c14b54396d)) + +## 1.0.0 (2025-03-20) + + +### ⚠ BREAKING CHANGES + +* initial commit + +### Features + +* initial commit ([8dcd49a](https://github.com/compwright/php-jwks/commit/8dcd49a177f6b9fc517749a85a8dbeaef004cc5f)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 35a51ba..5477eb5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,36 +6,36 @@ This is a very small library with a very limited scope but if you want to contri ### Reporting bugs -You can open [a new issue](https://github.com/Strobotti/php-jwk/issues) once you have checked one covering your issue hasn't been opened yet. +You can open [a new issue](https://github.com/compwright/php-jwks/issues) once you have checked one covering your issue hasn't been opened yet. ### Open a pull-request If you want to fix a bug or add a missing feature you can open a new pull-request. -Please note that you need a PHP 7.3 or later for using this library (running the tests requires at least php 8.2). +Please note that you need a PHP 8.3 or later for using this library. Basic steps: 1. Fork this repository -1. Clone it locally -1. Install dependencies with Composer +2. Clone it locally +3. Install dependencies with Composer ```bash $ composer install ``` -1. Create a branch on your fork -1. Commit & push -1. Open a pull-request from your branch -1. Profit +4. Create a branch on your fork +5. Commit & push +6. Open a pull-request from your branch +7. Profit Some guidelines: 1. Before committing make sure to format the code accordingly: ```bash - $ make php-cs-fixer-fix + $ make style ``` 1. Also make sure the tests pass successfully and you have sufficient coverage ```bash - $ make test-unit + $ make test ``` ### Git Commit Messages @@ -47,4 +47,4 @@ Some guidelines: ## License -[MIT](https://github.com/Strobotti/php-jwk/blob/master/LICENSE) +[MIT](https://github.com/compwright/php-jwks/blob/master/LICENSE) diff --git a/Makefile b/Makefile index 3fb11f0..49d3320 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,6 @@ -test-unit: +test: + vendor/bin/phpstan analyse --level 9 src tests php -d xdebug.mode=coverage ./vendor/bin/phpunit -php-cs-fixer: - ./vendor/bin/php-cs-fixer fix --verbose --dry-run --show-progress none --config .php_cs.php - -php-cs-fixer-fix: - ./vendor/bin/php-cs-fixer fix --verbose --show-progress none --config .php_cs.php +style: + PHP_CS_FIXER_IGNORE_ENV=1 vendor/bin/php-cs-fixer fix diff --git a/README.md b/README.md index 3e9a843..eb80b29 100644 --- a/README.md +++ b/README.md @@ -1,35 +1,27 @@ # php-jwk -[![Latest Stable Version](https://poser.pugx.org/strobotti/php-jwk/v/stable)](https://packagist.org/packages/strobotti/php-jwk) +[![Latest Stable Version](https://poser.pugx.org/compwright/php-jwks/v/stable)](https://packagist.org/packages/compwright/php-jwks) ![coverage](https://raw.githubusercontent.com/Strobotti/php-jwk/gh-pages/.badges/master/coverage.svg) -[![License](https://poser.pugx.org/strobotti/php-jwk/license)](https://packagist.org/packages/strobotti/php-jwk) +[![License](https://poser.pugx.org/compwright/php-jwks/license)](https://packagist.org/packages/compwright/php-jwks) -A small PHP library to handle JWKs (Json Web Keys) +JSON Web Key tools for PHP per [RFC-7517](https://tools.ietf.org/html/rfc7517) -This library helps to create json web key sets from PEM and is also able to pull out PEMs from json web key sets. - -Please note that **only RSA keys are supported at the moment!** - -See [JSON Web Key RFC](https://tools.ietf.org/html/rfc7517) for reference. +Inspired by https://github.com/Strobotti/php-jwk, but reimagined, simplified, and updated for PHP 8.4. ## Installation -This library requires PHP version 7.3 or higher and can be installed with composer: - ```bash -$ composer require strobotti/php-jwk +$ composer require compwright/php-jwks ``` ## Example usage -See full example [here](examples/full-flow.php). - ### Create a key-object from PEM ```php 'sig', - 'alg' => 'RS256', - 'kid' => 'eXaunmL', -]; +PEM; -$keyFactory = new Strobotti\JWK\KeyFactory(); -$key = $keyFactory->createFromPem($pem, $options); +$keyFactory = new Compwright\JWKS\KeyFactory(); +$key = $keyFactory->createFromPem($pem, Key::USE_SIGNATURE, 'eXaunmL'); -echo "$key"; +echo (string) $key; ``` Outputs: @@ -66,17 +52,15 @@ Outputs: } ``` -### Create a JWK set (jwks) from a key +### Create a JWK Set (JWKS) from a key ```php addKey($key); -echo "$keySet" ; - +echo (string) $keySet; ``` Outputs: @@ -96,17 +80,16 @@ Outputs: } ``` -### Get a key from keyset by `kid` and convert it to PEM +### Get a key from a keyset by `kid` and convert it to PEM ```php getKeyById('eXaunmL'); -$pem = (new \Strobotti\JWK\KeyConverter())->keyToPem($key); - -echo "$pem"; +$key = $keySet->getById('eXaunmL'); +$pem = $key->getPem(); +echo $pem; ``` Outputs: @@ -123,6 +106,10 @@ xwIDAQAB -----END PUBLIC KEY----- ``` -### Contributing +## Contributing See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. + +## License + +MIT License diff --git a/composer.json b/composer.json index 0e30423..8e65630 100644 --- a/composer.json +++ b/composer.json @@ -1,43 +1,41 @@ { - "name": "strobotti/php-jwk", - "description": "A small PHP library to handle JWKs (Json Web Keys)", + "name": "compwright/php-jwks", + "description": "JSON Web Key tools for PHP per RFC-7517", "type": "library", - "keywords": ["jwk", "jwks"], - "homepage": "https://github.com/Strobotti/php-jwk", + "keywords": [ + "jwk", + "jwks", + "rfc7517" + ], + "homepage": "https://github.com/compwright/php-jwks", "authors": [ { - "name": "Juha Jantunen", - "email": "juha@strobotti.com", - "homepage": "https://www.strobotti.com/", + "name": "Jonathon Hill", + "email": "jonathon@compwright.com", + "homepage": "https://compwright.com/", "role": "Developer" } ], "license": "MIT", "require": { - "php": ">=7.3.0", + "php": "^8.3.0 || ^8.4.0", "ext-json": "*", "ext-openssl": "*", "phpseclib/phpseclib": "^3.0" }, "autoload": { "psr-4": { - "Strobotti\\JWK\\": "src/" + "Compwright\\JWKS\\": "src/" } }, "autoload-dev": { "psr-4": { - "Strobotti\\JWK\\Tests\\": "tests/" + "Compwright\\JWKS\\": "tests/" } }, "require-dev": { - "ext-xml": "*", - "phpunit/phpunit": "^10.0", - "friendsofphp/php-cs-fixer": "3.54.0" - }, - "scripts": { - "test": "./vendor/bin/phpunit" - }, - "scripts-descriptions": { - "test": "Run all tests" + "friendsofphp/php-cs-fixer": "^3.72", + "phpstan/phpstan": "^2.1", + "phpunit/phpunit": "^10.5" } -} +} \ No newline at end of file diff --git a/composer.lock b/composer.lock index ecb6ed1..02ecbf9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,28 +4,28 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3dc8b3e205fb2a57b1ca08802ea8c034", + "content-hash": "c9404e10f1e73715596402939fa96cc3", "packages": [ { "name": "paragonie/constant_time_encoding", - "version": "v2.6.3", + "version": "v3.0.0", "source": { "type": "git", "url": "https://github.com/paragonie/constant_time_encoding.git", - "reference": "58c3f47f650c94ec05a151692652a868995d2938" + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/58c3f47f650c94ec05a151692652a868995d2938", - "reference": "58c3f47f650c94ec05a151692652a868995d2938", + "url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512", + "reference": "df1e7fde177501eee2037dd159cf04f5f301a512", "shasum": "" }, "require": { - "php": "^7|^8" + "php": "^8" }, "require-dev": { - "phpunit/phpunit": "^6|^7|^8|^9", - "vimeo/psalm": "^1|^2|^3|^4" + "phpunit/phpunit": "^9", + "vimeo/psalm": "^4|^5" }, "type": "library", "autoload": { @@ -71,7 +71,7 @@ "issues": "https://github.com/paragonie/constant_time_encoding/issues", "source": "https://github.com/paragonie/constant_time_encoding" }, - "time": "2022-06-14T06:56:20+00:00" + "time": "2024-05-08T12:36:18+00:00" }, { "name": "paragonie/random_compat", @@ -125,20 +125,20 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.37", + "version": "3.0.43", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8" + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/cfa2013d0f68c062055180dd4328cc8b9d1f30b8", - "reference": "cfa2013d0f68c062055180dd4328cc8b9d1f30b8", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/709ec107af3cb2f385b9617be72af8cf62441d02", + "reference": "709ec107af3cb2f385b9617be72af8cf62441d02", "shasum": "" }, "require": { - "paragonie/constant_time_encoding": "^1|^2", + "paragonie/constant_time_encoding": "^1|^2|^3", "paragonie/random_compat": "^1.4|^2.0|^9.99.99", "php": ">=5.6.1" }, @@ -215,7 +215,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.37" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.43" }, "funding": [ { @@ -231,34 +231,106 @@ "type": "tidelift" } ], - "time": "2024-03-03T02:14:58+00:00" + "time": "2024-12-14T21:12:59+00:00" } ], "packages-dev": [ + { + "name": "clue/ndjson-react", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/clue/reactphp-ndjson.git", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/clue/reactphp-ndjson/zipball/392dc165fce93b5bb5c637b67e59619223c931b0", + "reference": "392dc165fce93b5bb5c637b67e59619223c931b0", + "shasum": "" + }, + "require": { + "php": ">=5.3", + "react/stream": "^1.2" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35", + "react/event-loop": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Clue\\React\\NDJson\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering" + } + ], + "description": "Streaming newline-delimited JSON (NDJSON) parser and encoder for ReactPHP.", + "homepage": "https://github.com/clue/reactphp-ndjson", + "keywords": [ + "NDJSON", + "json", + "jsonlines", + "newline", + "reactphp", + "streaming" + ], + "support": { + "issues": "https://github.com/clue/reactphp-ndjson/issues", + "source": "https://github.com/clue/reactphp-ndjson/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://clue.engineering/support", + "type": "custom" + }, + { + "url": "https://github.com/clue", + "type": "github" + } + ], + "time": "2022-12-23T10:58:28+00:00" + }, { "name": "composer/pcre", - "version": "3.1.3", + "version": "3.3.2", "source": { "type": "git", "url": "https://github.com/composer/pcre.git", - "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8" + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/5b16e25a5355f1f3afdfc2f954a0a80aec4826a8", - "reference": "5b16e25a5355f1f3afdfc2f954a0a80aec4826a8", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", "shasum": "" }, "require": { "php": "^7.4 || ^8.0" }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, "require-dev": { - "phpstan/phpstan": "^1.3", - "phpstan/phpstan-strict-rules": "^1.1", - "symfony/phpunit-bridge": "^5" + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" }, "type": "library", "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, "branch-alias": { "dev-main": "3.x-dev" } @@ -288,7 +360,7 @@ ], "support": { "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.1.3" + "source": "https://github.com/composer/pcre/tree/3.3.2" }, "funding": [ { @@ -304,28 +376,28 @@ "type": "tidelift" } ], - "time": "2024-03-19T10:26:25+00:00" + "time": "2024-11-12T16:29:46+00:00" }, { "name": "composer/semver", - "version": "3.4.0", + "version": "3.4.3", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32" + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/35e8d0af4486141bc745f23a29cc2091eb624a32", - "reference": "35e8d0af4486141bc745f23a29cc2091eb624a32", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", "shasum": "" }, "require": { "php": "^5.3.2 || ^7.0 || ^8.0" }, "require-dev": { - "phpstan/phpstan": "^1.4", - "symfony/phpunit-bridge": "^4.2 || ^5" + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" }, "type": "library", "extra": { @@ -369,7 +441,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.0" + "source": "https://github.com/composer/semver/tree/3.4.3" }, "funding": [ { @@ -385,20 +457,20 @@ "type": "tidelift" } ], - "time": "2023-08-31T09:50:34+00:00" + "time": "2024-09-19T14:15:21+00:00" }, { "name": "composer/xdebug-handler", - "version": "3.0.4", + "version": "3.0.5", "source": { "type": "git", "url": "https://github.com/composer/xdebug-handler.git", - "reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255" + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/4f988f8fdf580d53bdb2d1278fe93d1ed5462255", - "reference": "4f988f8fdf580d53bdb2d1278fe93d1ed5462255", + "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", + "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", "shasum": "" }, "require": { @@ -435,7 +507,7 @@ "support": { "irc": "ircs://irc.libera.chat:6697/composer", "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.4" + "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" }, "funding": [ { @@ -451,54 +523,170 @@ "type": "tidelift" } ], - "time": "2024-03-26T18:29:49+00:00" + "time": "2024-05-06T16:37:16+00:00" + }, + { + "name": "evenement/evenement", + "version": "v3.0.2", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/0a16b0d71ab13284339abb99d9d2bd813640efbc", + "reference": "0a16b0d71ab13284339abb99d9d2bd813640efbc", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9 || ^6" + }, + "type": "library", + "autoload": { + "psr-4": { + "Evenement\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "support": { + "issues": "https://github.com/igorw/evenement/issues", + "source": "https://github.com/igorw/evenement/tree/v3.0.2" + }, + "time": "2023-08-08T05:53:35+00:00" + }, + { + "name": "fidry/cpu-core-counter", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/theofidry/cpu-core-counter.git", + "reference": "8520451a140d3f46ac33042715115e290cf5785f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", + "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "fidry/makefile": "^0.2.0", + "fidry/php-cs-fixer-config": "^1.1.2", + "phpstan/extension-installer": "^1.2.0", + "phpstan/phpstan": "^1.9.2", + "phpstan/phpstan-deprecation-rules": "^1.0.0", + "phpstan/phpstan-phpunit": "^1.2.2", + "phpstan/phpstan-strict-rules": "^1.4.4", + "phpunit/phpunit": "^8.5.31 || ^9.5.26", + "webmozarts/strict-phpunit": "^7.5" + }, + "type": "library", + "autoload": { + "psr-4": { + "Fidry\\CpuCoreCounter\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Théo FIDRY", + "email": "theo.fidry@gmail.com" + } + ], + "description": "Tiny utility to get the number of CPU cores.", + "keywords": [ + "CPU", + "core" + ], + "support": { + "issues": "https://github.com/theofidry/cpu-core-counter/issues", + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + }, + "funding": [ + { + "url": "https://github.com/theofidry", + "type": "github" + } + ], + "time": "2024-08-06T10:04:20+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.54.0", + "version": "v3.73.1", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08" + "reference": "ffcb8200a42045e65049af7910cfd022f631b064" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/2aecbc8640d7906c38777b3dcab6f4ca79004d08", - "reference": "2aecbc8640d7906c38777b3dcab6f4ca79004d08", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/ffcb8200a42045e65049af7910cfd022f631b064", + "reference": "ffcb8200a42045e65049af7910cfd022f631b064", "shasum": "" }, "require": { + "clue/ndjson-react": "^1.0", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.3", "ext-filter": "*", + "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", + "fidry/cpu-core-counter": "^1.2", "php": "^7.4 || ^8.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0", - "symfony/console": "^5.4 || ^6.0 || ^7.0", - "symfony/event-dispatcher": "^5.4 || ^6.0 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.0 || ^7.0", - "symfony/finder": "^5.4 || ^6.0 || ^7.0", - "symfony/options-resolver": "^5.4 || ^6.0 || ^7.0", - "symfony/polyfill-mbstring": "^1.28", - "symfony/polyfill-php80": "^1.28", - "symfony/polyfill-php81": "^1.28", - "symfony/process": "^5.4 || ^6.0 || ^7.0", - "symfony/stopwatch": "^5.4 || ^6.0 || ^7.0" + "react/child-process": "^0.6.5", + "react/event-loop": "^1.0", + "react/promise": "^2.0 || ^3.0", + "react/socket": "^1.0", + "react/stream": "^1.0", + "sebastian/diff": "^4.0 || ^5.1 || ^6.0 || ^7.0", + "symfony/console": "^5.4 || ^6.4 || ^7.0", + "symfony/event-dispatcher": "^5.4 || ^6.4 || ^7.0", + "symfony/filesystem": "^5.4 || ^6.4 || ^7.0", + "symfony/finder": "^5.4 || ^6.4 || ^7.0", + "symfony/options-resolver": "^5.4 || ^6.4 || ^7.0", + "symfony/polyfill-mbstring": "^1.31", + "symfony/polyfill-php80": "^1.31", + "symfony/polyfill-php81": "^1.31", + "symfony/process": "^5.4 || ^6.4 || ^7.2", + "symfony/stopwatch": "^5.4 || ^6.4 || ^7.0" }, "require-dev": { - "facile-it/paraunit": "^1.3 || ^2.0", - "infection/infection": "^0.27.11", - "justinrainbow/json-schema": "^5.2", + "facile-it/paraunit": "^1.3.1 || ^2.6", + "infection/infection": "^0.29.14", + "justinrainbow/json-schema": "^5.3 || ^6.2", "keradus/cli-executor": "^2.1", - "mikey179/vfsstream": "^1.6.11", + "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.7", "php-cs-fixer/accessible-object": "^1.1", - "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4", - "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4", - "phpunit/phpunit": "^9.6 || ^10.5.5 || ^11.0.2", - "symfony/var-dumper": "^5.4 || ^6.0 || ^7.0", - "symfony/yaml": "^5.4 || ^6.0 || ^7.0" + "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", + "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", + "phpunit/phpunit": "^9.6.22 || ^10.5.45 || ^11.5.12", + "symfony/var-dumper": "^5.4.48 || ^6.4.18 || ^7.2.3", + "symfony/yaml": "^5.4.45 || ^6.4.18 || ^7.2.3" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -511,7 +699,10 @@ "autoload": { "psr-4": { "PhpCsFixer\\": "src/" - } + }, + "exclude-from-classmap": [ + "src/Fixer/Internal/*" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -536,7 +727,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.54.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.73.1" }, "funding": [ { @@ -544,20 +735,20 @@ "type": "github" } ], - "time": "2024-04-17T08:12:13+00:00" + "time": "2025-03-19T23:42:16+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.11.1", + "version": "1.13.0", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" + "reference": "024473a478be9df5fdaca2c793f2232fe788e414" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", - "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", + "reference": "024473a478be9df5fdaca2c793f2232fe788e414", "shasum": "" }, "require": { @@ -565,11 +756,12 @@ }, "conflict": { "doctrine/collections": "<1.6.8", - "doctrine/common": "<2.13.3 || >=3,<3.2.2" + "doctrine/common": "<2.13.3 || >=3 <3.2.2" }, "require-dev": { "doctrine/collections": "^1.6.8", "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", @@ -595,7 +787,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" }, "funding": [ { @@ -603,20 +795,20 @@ "type": "tidelift" } ], - "time": "2023-03-08T13:26:56+00:00" + "time": "2025-02-12T12:17:51+00:00" }, { "name": "nikic/php-parser", - "version": "v5.0.2", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", - "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -627,7 +819,7 @@ }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -659,9 +851,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-03-05T20:51:40+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "phar-io/manifest", @@ -781,34 +973,92 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "phpstan/phpstan", + "version": "2.1.8", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/f9adff3b87c03b12cc7e46a30a524648e497758f", + "reference": "f9adff3b87c03b12cc7e46a30a524648e497758f", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-03-09T09:30:48+00:00" + }, { "name": "phpunit/php-code-coverage", - "version": "10.1.14", + "version": "10.1.16", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b" + "reference": "7e308268858ed6baedc8704a304727d20bc07c77" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", - "reference": "e3f51450ebffe8e0efdf7346ae966a656f7d5e5b", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/7e308268858ed6baedc8704a304727d20bc07c77", + "reference": "7e308268858ed6baedc8704a304727d20bc07c77", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.18 || ^5.0", + "nikic/php-parser": "^4.19.1 || ^5.1.0", "php": ">=8.1", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-text-template": "^3.0", - "sebastian/code-unit-reverse-lookup": "^3.0", - "sebastian/complexity": "^3.0", - "sebastian/environment": "^6.0", - "sebastian/lines-of-code": "^2.0", - "sebastian/version": "^4.0", - "theseer/tokenizer": "^1.2.0" + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-text-template": "^3.0.1", + "sebastian/code-unit-reverse-lookup": "^3.0.0", + "sebastian/complexity": "^3.2.0", + "sebastian/environment": "^6.1.0", + "sebastian/lines-of-code": "^2.0.2", + "sebastian/version": "^4.0.1", + "theseer/tokenizer": "^1.2.3" }, "require-dev": { "phpunit/phpunit": "^10.1" @@ -820,7 +1070,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.1-dev" + "dev-main": "10.1.x-dev" } }, "autoload": { @@ -849,7 +1099,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.14" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/10.1.16" }, "funding": [ { @@ -857,7 +1107,7 @@ "type": "github" } ], - "time": "2024-03-12T15:33:41+00:00" + "time": "2024-08-22T04:31:57+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1104,16 +1354,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.20", + "version": "10.5.45", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3" + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/547d314dc24ec1e177720d45c6263fb226cc2ae3", - "reference": "547d314dc24ec1e177720d45c6263fb226cc2ae3", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/bd68a781d8e30348bc297449f5234b3458267ae8", + "reference": "bd68a781d8e30348bc297449f5234b3458267ae8", "shasum": "" }, "require": { @@ -1123,26 +1373,26 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.10.1", - "phar-io/manifest": "^2.0.3", - "phar-io/version": "^3.0.2", + "myclabs/deep-copy": "^1.12.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", "php": ">=8.1", - "phpunit/php-code-coverage": "^10.1.5", - "phpunit/php-file-iterator": "^4.0", - "phpunit/php-invoker": "^4.0", - "phpunit/php-text-template": "^3.0", - "phpunit/php-timer": "^6.0", - "sebastian/cli-parser": "^2.0", - "sebastian/code-unit": "^2.0", - "sebastian/comparator": "^5.0", - "sebastian/diff": "^5.0", - "sebastian/environment": "^6.0", - "sebastian/exporter": "^5.1", - "sebastian/global-state": "^6.0.1", - "sebastian/object-enumerator": "^5.0", - "sebastian/recursion-context": "^5.0", - "sebastian/type": "^4.0", - "sebastian/version": "^4.0" + "phpunit/php-code-coverage": "^10.1.16", + "phpunit/php-file-iterator": "^4.1.0", + "phpunit/php-invoker": "^4.0.0", + "phpunit/php-text-template": "^3.0.1", + "phpunit/php-timer": "^6.0.0", + "sebastian/cli-parser": "^2.0.1", + "sebastian/code-unit": "^2.0.0", + "sebastian/comparator": "^5.0.3", + "sebastian/diff": "^5.1.1", + "sebastian/environment": "^6.1.0", + "sebastian/exporter": "^5.1.2", + "sebastian/global-state": "^6.0.2", + "sebastian/object-enumerator": "^5.0.0", + "sebastian/recursion-context": "^5.0.0", + "sebastian/type": "^4.0.0", + "sebastian/version": "^4.0.1" }, "suggest": { "ext-soap": "To be able to generate mocks based on WSDL files" @@ -1185,7 +1435,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.20" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.45" }, "funding": [ { @@ -1201,7 +1451,7 @@ "type": "tidelift" } ], - "time": "2024-04-24T06:32:35+00:00" + "time": "2025-02-06T16:08:12+00:00" }, { "name": "psr/container", @@ -1308,16 +1558,16 @@ }, { "name": "psr/log", - "version": "3.0.0", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001" + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe5ea303b0887d5caefd3d431c3e61ad47037001", - "reference": "fe5ea303b0887d5caefd3d431c3e61ad47037001", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", "shasum": "" }, "require": { @@ -1352,9 +1602,535 @@ "psr-3" ], "support": { - "source": "https://github.com/php-fig/log/tree/3.0.0" + "source": "https://github.com/php-fig/log/tree/3.0.2" }, - "time": "2021-07-14T16:46:02+00:00" + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "react/cache", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/cache.git", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/cache/zipball/d47c472b64aa5608225f47965a484b75c7817d5b", + "reference": "d47c472b64aa5608225f47965a484b75c7817d5b", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/promise": "^3.0 || ^2.0 || ^1.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.5 || ^5.7 || ^4.8.35" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, Promise-based cache interface for ReactPHP", + "keywords": [ + "cache", + "caching", + "promise", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/cache/issues", + "source": "https://github.com/reactphp/cache/tree/v1.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2022-11-30T15:59:55+00:00" + }, + { + "name": "react/child-process", + "version": "v0.6.6", + "source": { + "type": "git", + "url": "https://github.com/reactphp/child-process.git", + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/child-process/zipball/1721e2b93d89b745664353b9cfc8f155ba8a6159", + "reference": "1721e2b93d89b745664353b9cfc8f155ba8a6159", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/event-loop": "^1.2", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/socket": "^1.16", + "sebastian/environment": "^5.0 || ^3.0 || ^2.0 || ^1.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\ChildProcess\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven library for executing child processes with ReactPHP.", + "keywords": [ + "event-driven", + "process", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/child-process/issues", + "source": "https://github.com/reactphp/child-process/tree/v0.6.6" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2025-01-01T16:37:48+00:00" + }, + { + "name": "react/dns", + "version": "v1.13.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/dns.git", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/dns/zipball/eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "reference": "eb8ae001b5a455665c89c1df97f6fb682f8fb0f5", + "shasum": "" + }, + "require": { + "php": ">=5.3.0", + "react/cache": "^1.0 || ^0.6 || ^0.5", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.7 || ^1.2.1" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3 || ^2", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Dns\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async DNS resolver for ReactPHP", + "keywords": [ + "async", + "dns", + "dns-resolver", + "reactphp" + ], + "support": { + "issues": "https://github.com/reactphp/dns/issues", + "source": "https://github.com/reactphp/dns/tree/v1.13.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-13T14:18:03+00:00" + }, + { + "name": "react/event-loop", + "version": "v1.5.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/event-loop.git", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/event-loop/zipball/bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "reference": "bbe0bd8c51ffc05ee43f1729087ed3bdf7d53354", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "suggest": { + "ext-pcntl": "For signal handling support when using the StreamSelectLoop" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\EventLoop\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "ReactPHP's core reactor event loop that libraries can use for evented I/O.", + "keywords": [ + "asynchronous", + "event-loop" + ], + "support": { + "issues": "https://github.com/reactphp/event-loop/issues", + "source": "https://github.com/reactphp/event-loop/tree/v1.5.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2023-11-13T13:48:05+00:00" + }, + { + "name": "react/promise", + "version": "v3.2.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", + "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "shasum": "" + }, + "require": { + "php": ">=7.1.0" + }, + "require-dev": { + "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpunit/phpunit": "^9.6 || ^7.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "React\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "keywords": [ + "promise", + "promises" + ], + "support": { + "issues": "https://github.com/reactphp/promise/issues", + "source": "https://github.com/reactphp/promise/tree/v3.2.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-05-24T10:39:05+00:00" + }, + { + "name": "react/socket", + "version": "v1.16.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/socket.git", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/socket/zipball/23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "reference": "23e4ff33ea3e160d2d1f59a0e6050e4b0fb0eac1", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.0", + "react/dns": "^1.13", + "react/event-loop": "^1.2", + "react/promise": "^3.2 || ^2.6 || ^1.2.1", + "react/stream": "^1.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", + "react/async": "^4.3 || ^3.3 || ^2", + "react/promise-stream": "^1.4", + "react/promise-timer": "^1.11" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Socket\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Async, streaming plaintext TCP/IP and secure TLS socket server and client connections for ReactPHP", + "keywords": [ + "Connection", + "Socket", + "async", + "reactphp", + "stream" + ], + "support": { + "issues": "https://github.com/reactphp/socket/issues", + "source": "https://github.com/reactphp/socket/tree/v1.16.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-07-26T10:38:09+00:00" + }, + { + "name": "react/stream", + "version": "v1.4.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/stream.git", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/stream/zipball/1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "reference": "1e5b0acb8fe55143b5b426817155190eb6f5b18d", + "shasum": "" + }, + "require": { + "evenement/evenement": "^3.0 || ^2.0 || ^1.0", + "php": ">=5.3.8", + "react/event-loop": "^1.2" + }, + "require-dev": { + "clue/stream-filter": "~1.2", + "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36" + }, + "type": "library", + "autoload": { + "psr-4": { + "React\\Stream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Christian Lück", + "email": "christian@clue.engineering", + "homepage": "https://clue.engineering/" + }, + { + "name": "Cees-Jan Kiewiet", + "email": "reactphp@ceesjankiewiet.nl", + "homepage": "https://wyrihaximus.net/" + }, + { + "name": "Jan Sorgalla", + "email": "jsorgalla@gmail.com", + "homepage": "https://sorgalla.com/" + }, + { + "name": "Chris Boden", + "email": "cboden@gmail.com", + "homepage": "https://cboden.dev/" + } + ], + "description": "Event-driven readable and writable streams for non-blocking I/O in ReactPHP", + "keywords": [ + "event-driven", + "io", + "non-blocking", + "pipe", + "reactphp", + "readable", + "stream", + "writable" + ], + "support": { + "issues": "https://github.com/reactphp/stream/issues", + "source": "https://github.com/reactphp/stream/tree/v1.4.0" + }, + "funding": [ + { + "url": "https://opencollective.com/reactphp", + "type": "open_collective" + } + ], + "time": "2024-06-11T12:45:25+00:00" }, { "name": "sebastian/cli-parser", @@ -1526,16 +2302,16 @@ }, { "name": "sebastian/comparator", - "version": "5.0.1", + "version": "5.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372" + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2db5010a484d53ebf536087a70b4a5423c102372", - "reference": "2db5010a484d53ebf536087a70b4a5423c102372", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", "shasum": "" }, "require": { @@ -1546,7 +2322,7 @@ "sebastian/exporter": "^5.0" }, "require-dev": { - "phpunit/phpunit": "^10.3" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -1591,7 +2367,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.1" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" }, "funding": [ { @@ -1599,7 +2375,7 @@ "type": "github" } ], - "time": "2023-08-14T13:18:12+00:00" + "time": "2024-10-18T14:56:07+00:00" }, { "name": "sebastian/complexity", @@ -2274,16 +3050,16 @@ }, { "name": "symfony/console", - "version": "v7.0.7", + "version": "v7.2.1", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986" + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c981e0e9380ce9f146416bde3150c79197ce9986", - "reference": "c981e0e9380ce9f146416bde3150c79197ce9986", + "url": "https://api.github.com/repos/symfony/console/zipball/fefcc18c0f5d0efe3ab3152f15857298868dc2c3", + "reference": "fefcc18c0f5d0efe3ab3152f15857298868dc2c3", "shasum": "" }, "require": { @@ -2347,7 +3123,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.0.7" + "source": "https://github.com/symfony/console/tree/v7.2.1" }, "funding": [ { @@ -2363,20 +3139,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-12-11T03:49:26+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", "shasum": "" }, "require": { @@ -2384,12 +3160,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -2414,7 +3190,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" }, "funding": [ { @@ -2430,20 +3206,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.0.7", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9" + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/db2a7fab994d67d92356bb39c367db115d9d30f9", - "reference": "db2a7fab994d67d92356bb39c367db115d9d30f9", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", "shasum": "" }, "require": { @@ -2494,7 +3270,7 @@ "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/v7.0.7" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" }, "funding": [ { @@ -2510,20 +3286,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-09-25T14:21:43+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v3.4.2", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "4e64b49bf370ade88e567de29465762e316e4224" + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/4e64b49bf370ade88e567de29465762e316e4224", - "reference": "4e64b49bf370ade88e567de29465762e316e4224", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", "shasum": "" }, "require": { @@ -2532,12 +3308,12 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -2570,7 +3346,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" }, "funding": [ { @@ -2586,26 +3362,28 @@ "type": "tidelift" } ], - "time": "2024-01-23T14:51:35+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/filesystem", - "version": "v7.0.7", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5" + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/cc168be6fbdcdf3401f50ae863ee3818ed4338f5", - "reference": "cc168be6fbdcdf3401f50ae863ee3818ed4338f5", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", "shasum": "" }, "require": { "php": ">=8.2", "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { "symfony/process": "^6.4|^7.0" }, "type": "library", @@ -2634,7 +3412,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.0.7" + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" }, "funding": [ { @@ -2650,20 +3428,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-10-25T15:15:23+00:00" }, { "name": "symfony/finder", - "version": "v7.0.7", + "version": "v7.2.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c" + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/4d58f0f4fe95a30d7b538d71197135483560b97c", - "reference": "4d58f0f4fe95a30d7b538d71197135483560b97c", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", "shasum": "" }, "require": { @@ -2698,7 +3476,7 @@ "description": "Finds files and directories via an intuitive fluent interface", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/finder/tree/v7.0.7" + "source": "https://github.com/symfony/finder/tree/v7.2.2" }, "funding": [ { @@ -2714,20 +3492,20 @@ "type": "tidelift" } ], - "time": "2024-04-28T11:44:19+00:00" + "time": "2024-12-30T19:00:17+00:00" }, { "name": "symfony/options-resolver", - "version": "v7.0.7", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "23cc173858776ad451e31f053b1c9f47840b2cfa" + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/23cc173858776ad451e31f053b1c9f47840b2cfa", - "reference": "23cc173858776ad451e31f053b1c9f47840b2cfa", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/7da8fbac9dcfef75ffc212235d76b2754ce0cf50", + "reference": "7da8fbac9dcfef75ffc212235d76b2754ce0cf50", "shasum": "" }, "require": { @@ -2765,7 +3543,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.0.7" + "source": "https://github.com/symfony/options-resolver/tree/v7.2.0" }, "funding": [ { @@ -2781,24 +3559,24 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-11-20T11:17:29+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-ctype": "*" @@ -2809,8 +3587,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2844,7 +3622,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0" }, "funding": [ { @@ -2860,24 +3638,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f" + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/32a9da87d7b3245e09ac426c83d334ae9f06f80f", - "reference": "32a9da87d7b3245e09ac426c83d334ae9f06f80f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -2885,8 +3663,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2922,7 +3700,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.31.0" }, "funding": [ { @@ -2938,24 +3716,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d" + "reference": "3833d7255cc303546435cb650316bff708a1c75c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/bc45c394692b948b4d383a08d7753968bed9a83d", - "reference": "bc45c394692b948b4d383a08d7753968bed9a83d", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "suggest": { "ext-intl": "For best performance" @@ -2963,8 +3741,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3003,7 +3781,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.31.0" }, "funding": [ { @@ -3019,24 +3797,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -3047,8 +3825,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3083,7 +3861,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -3099,30 +3877,30 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3163,7 +3941,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -3179,30 +3957,30 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d" + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/c565ad1e63f30e7477fc40738343c62b40bc672d", - "reference": "c565ad1e63f30e7477fc40738343c62b40bc672d", + "url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", + "reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -3239,7 +4017,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0" }, "funding": [ { @@ -3255,20 +4033,20 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/process", - "version": "v7.0.7", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0" + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/3839e56b94dd1dbd13235d27504e66baf23faba0", - "reference": "3839e56b94dd1dbd13235d27504e66baf23faba0", + "url": "https://api.github.com/repos/symfony/process/zipball/d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", + "reference": "d8f411ff3c7ddc4ae9166fb388d1190a2df5b5cf", "shasum": "" }, "require": { @@ -3300,7 +4078,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/process/tree/v7.0.7" + "source": "https://github.com/symfony/process/tree/v7.2.4" }, "funding": [ { @@ -3316,37 +4094,38 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2025-02-05T08:33:46+00:00" }, { "name": "symfony/service-contracts", - "version": "v3.4.2", + "version": "v3.5.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "11bbf19a0fb7b36345861e85c5768844c552906e" + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/11bbf19a0fb7b36345861e85c5768844c552906e", - "reference": "11bbf19a0fb7b36345861e85c5768844c552906e", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", "shasum": "" }, "require": { "php": ">=8.1", - "psr/container": "^1.1|^2.0" + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" }, "conflict": { "ext-psr": "<1.1|>=2" }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "3.4-dev" - }, "thanks": { - "name": "symfony/contracts", - "url": "https://github.com/symfony/contracts" + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" } }, "autoload": { @@ -3382,7 +4161,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.4.2" + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" }, "funding": [ { @@ -3398,20 +4177,20 @@ "type": "tidelift" } ], - "time": "2023-12-19T21:51:00+00:00" + "time": "2024-09-25T14:20:29+00:00" }, { "name": "symfony/stopwatch", - "version": "v7.0.7", + "version": "v7.2.4", "source": { "type": "git", "url": "https://github.com/symfony/stopwatch.git", - "reference": "41a7a24aa1dc82adf46a06bc292d1923acfe6b84" + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/stopwatch/zipball/41a7a24aa1dc82adf46a06bc292d1923acfe6b84", - "reference": "41a7a24aa1dc82adf46a06bc292d1923acfe6b84", + "url": "https://api.github.com/repos/symfony/stopwatch/zipball/5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", + "reference": "5a49289e2b308214c8b9c2fda4ea454d8b8ad7cd", "shasum": "" }, "require": { @@ -3444,7 +4223,7 @@ "description": "Provides a way to profile code", "homepage": "https://symfony.com/", "support": { - "source": "https://github.com/symfony/stopwatch/tree/v7.0.7" + "source": "https://github.com/symfony/stopwatch/tree/v7.2.4" }, "funding": [ { @@ -3460,20 +4239,20 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2025-02-24T10:49:57+00:00" }, { "name": "symfony/string", - "version": "v7.0.7", + "version": "v7.2.0", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63" + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e405b5424dc2528e02e31ba26b83a79fd4eb8f63", - "reference": "e405b5424dc2528e02e31ba26b83a79fd4eb8f63", + "url": "https://api.github.com/repos/symfony/string/zipball/446e0d146f991dde3e73f45f2c97a9faad773c82", + "reference": "446e0d146f991dde3e73f45f2c97a9faad773c82", "shasum": "" }, "require": { @@ -3487,6 +4266,7 @@ "symfony/translation-contracts": "<2.5" }, "require-dev": { + "symfony/emoji": "^7.1", "symfony/error-handler": "^6.4|^7.0", "symfony/http-client": "^6.4|^7.0", "symfony/intl": "^6.4|^7.0", @@ -3530,7 +4310,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.0.7" + "source": "https://github.com/symfony/string/tree/v7.2.0" }, "funding": [ { @@ -3546,7 +4326,7 @@ "type": "tidelift" } ], - "time": "2024-04-18T09:29:19+00:00" + "time": "2024-11-13T13:31:26+00:00" }, { "name": "theseer/tokenizer", @@ -3601,16 +4381,14 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.3.0", + "php": "^8.3.0 || ^8.4.0", "ext-json": "*", "ext-openssl": "*" }, - "platform-dev": { - "ext-xml": "*" - }, + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/examples/full-flow.php b/examples/full-flow.php deleted file mode 100644 index ab37401..0000000 --- a/examples/full-flow.php +++ /dev/null @@ -1,44 +0,0 @@ - 'sig', - 'alg' => 'RS256', - 'kid' => 'eXaunmL', -]; - -$keyFactory = new KeyFactory(); -$key = $keyFactory->createFromPem($pem, $options); - -echo $key . PHP_EOL . PHP_EOL; - -echo "Adding the key to the KeySet:" . PHP_EOL; - -$keySet = new \Strobotti\JWK\KeySet(); -$keySet->addKey($key); - -echo $keySet . PHP_EOL . PHP_EOL; - -echo "Fetching the key by it's ID (`kid`) and convert it back to PEM:" . PHP_EOL; - -$key = $keySet->getKeyById('eXaunmL'); -$pem = (new \Strobotti\JWK\KeyConverter())->keyToPem($key); - -echo $pem . PHP_EOL . PHP_EOL; diff --git a/src/Base64Url.php b/src/Base64Url.php new file mode 100644 index 0000000..25544f7 --- /dev/null +++ b/src/Base64Url.php @@ -0,0 +1,19 @@ + + */ + public function toArray(): array + { + // @phpstan-ignore-next-line return.type + return get_object_vars($this); + } +} diff --git a/src/Key/AbstractKey.php b/src/Key/AbstractKey.php deleted file mode 100644 index dfa890d..0000000 --- a/src/Key/AbstractKey.php +++ /dev/null @@ -1,192 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ -abstract class AbstractKey implements KeyInterface -{ - /** - * The key type. - * - * @var string - */ - private $kty; - - /** - * The key ID. - * - * @var null|string - */ - private $kid; - - /** - * The public key use. - * - * @var null|string - */ - private $use; - - /** - * The algorithm. - * - * @var string - */ - private $alg; - - /** - * @since 1.0.0 - * - * @return false|string - */ - public function __toString() - { - return \json_encode($this->jsonSerialize(), JSON_PRETTY_PRINT); - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 Protected setter - * @since 1.2.0 Public setter - */ - public function setKeyType(string $kty): KeyInterface - { - $this->kty = $kty; - - return $this; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - */ - public function getKeyType(): string - { - return $this->kty; - } - - /** - * {@inheritdoc} - * - * @since 1.2.0 - */ - public function setKeyId(?string $kid): KeyInterface - { - $this->kid = $kid; - - return $this; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - */ - public function getKeyId(): ?string - { - return $this->kid; - } - - /** - * {@inheritdoc} - * - * @since 1.2.0 - */ - public function setPublicKeyUse(?string $use): KeyInterface - { - $this->use = $use; - - return $this; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - */ - public function getPublicKeyUse(): ?string - { - return $this->use; - } - - /** - * {@inheritdoc} - * - * @since 1.2.0 - */ - public function setAlgorithm(string $alg): KeyInterface - { - $this->alg = $alg; - - return $this; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - */ - public function getAlgorithm(): string - { - return $this->alg; - } - - /** - * Returns an array presentation of the key. - * - * @since 1.0.0 - * - * @return array An assoc to be passed to json_encode - */ - public function jsonSerialize(): array - { - $assoc = [ - 'kty' => $this->kty, - 'use' => $this->use, - 'alg' => $this->alg, - ]; - - if (null !== $this->kid) { - $assoc['kid'] = $this->kid; - } - - return $assoc; - } - - /** - * @since 1.0.0 - */ - public static function createFromJSON(string $json, KeyInterface $prototype = null): KeyInterface - { - $assoc = \json_decode($json, true); - - if ($prototype) { - $instance = clone $prototype; - } else { - $instance = new static(); - } - - foreach ($assoc as $key => $value) { - if (!\property_exists($instance, $key)) { - continue; - } - - try { - $instance->{$key} = $value; - } catch (\Throwable $e) { - // only set what you can - } - } - - return $instance; - } -} diff --git a/src/Key/KeyInterface.php b/src/Key/KeyInterface.php deleted file mode 100644 index 0c890cf..0000000 --- a/src/Key/KeyInterface.php +++ /dev/null @@ -1,116 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - * - * @method array jsonSerialize() - */ -interface KeyInterface extends \JsonSerializable -{ - /** - * @since 1.0.0 - */ - public const KEY_TYPE_RSA = 'RSA'; - - /** - * @since 1.0.0 - * - * @todo Model currently not implemented - */ - public const KEY_TYPE_OKP = 'OKP'; - - /** - * @since 1.0.0 - * - * @todo Model currently not implemented - */ - public const KEY_TYPE_EC = 'EC'; - - public const PUBLIC_KEY_USE_SIGNATURE = 'sig'; - public const PUBLIC_KEY_USE_ENCRYPTION = 'enc'; - - public const ALGORITHM_RS256 = 'RS256'; - - /** - * Converts this key to a string. - * - * @since 1.0.0 - * - * @return bool|string - */ - public function __toString(); - - /** - * Sets the key type, ie. the value for the `kty` field. - * - * See the KEY_TYPE_* constants for reference. - * - * @return KeyInterface - * - * @since 1.2.0 - */ - public function setKeyType(string $kty): self; - - /** - * Gets the key type, ie. the value of the `kty` field. - * - * @since 1.0.0 - */ - public function getKeyType(): string; - - /** - * Sets the key id, ie. the value of the `kid` field. - * - * @return KeyInterface - * - * @since 1.2.0 - */ - public function setKeyId(?string $kid): self; - - /** - * Gets the key id, ie. the value of the `kid` field. - * - * @since 1.0.0 - */ - public function getKeyId(): ?string; - - /** - * Sets the public key use, ie. the value of the `use` field. - * - * @return KeyInterface - * - * @since 1.2.0 - */ - public function setPublicKeyUse(?string $use): self; - - /** - * Gets the public key use, ie. the value of the `use` field. - * - * @since 1.0.0 - */ - public function getPublicKeyUse(): ?string; - - /** - * Sets the cryptographic algorithm used to sign the key, ie. the value of the `alg` field. - * - * @return KeyInterface - * - * @since 1.2.0 - */ - public function setAlgorithm(string $alg): self; - - /** - * Gets the cryptographic algorithm used to sign the key, ie. the value of the `alg` field. - * - * @since 1.0.0 - */ - public function getAlgorithm(): string; -} diff --git a/src/Key/Rsa.php b/src/Key/Rsa.php deleted file mode 100644 index 89c9ac2..0000000 --- a/src/Key/Rsa.php +++ /dev/null @@ -1,123 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ -class Rsa extends AbstractKey -{ - /** - * The modulus for the RSA public key. - * - * @var string - */ - private $n; - - /** - * The exponent for the RSA public key. - * - * @var string - */ - private $e; - - /** - * Rsa key constructor. - */ - public function __construct() - { - $this->setKeyType(KeyInterface::KEY_TYPE_RSA); - } - - /** - * Sets the exponent for the RSA public key, ie. the `e` field. - * - * @since 1.2.0 - */ - public function setExponent(string $e): self - { - $this->e = $e; - - return $this; - } - - /** - * Returns the exponent for the RSA public key. - * - * @since 1.0.0 - */ - public function getExponent(): string - { - return $this->e; - } - - /** - * Sets the modulus for the RSA public key, ie. the `n` field. - * - * @since 1.2.0 - */ - public function setModulus(string $n): KeyInterface - { - $this->n = $n; - - return $this; - } - - /** - * Returns the modulus for the RSA public key, ie. the `n`field. - * - * @since 1.0.0 - */ - public function getModulus(): string - { - return $this->n; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - */ - public function jsonSerialize(): array - { - $assoc = parent::jsonSerialize(); - $assoc['n'] = $this->n; - $assoc['e'] = $this->e; - - return $assoc; - } - - /** - * {@inheritdoc} - * - * @since 1.0.0 - * - * @return self - */ - public static function createFromJSON(string $json, KeyInterface $prototype = null): KeyInterface - { - if (!$prototype instanceof self) { - $prototype = new static(); - } - - $instance = parent::createFromJSON($json, $prototype); - - $assoc = \json_decode($json, true); - - foreach ($assoc as $key => $value) { - if (!\property_exists($instance, $key)) { - continue; - } - - $instance->{$key} = $value; - } - - return $instance; - } -} diff --git a/src/KeyConverter.php b/src/KeyConverter.php deleted file mode 100644 index 440846c..0000000 --- a/src/KeyConverter.php +++ /dev/null @@ -1,54 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ -class KeyConverter -{ - /** - * @var Base64UrlConverterInterface - */ - private $base64UrlConverter; - - /** - * KeyConverter constructor. - */ - public function __construct() - { - $this->base64UrlConverter = new Base64UrlConverter(); - } - - /** - * @since 1.0.0 - */ - public function keyToPem(KeyInterface $key): string - { - if (!$key instanceof RsaKey) { - throw new \InvalidArgumentException(); - } - - $modulus = $this->base64UrlConverter->decode($key->getModulus(), true); - - $rsa = PublicKeyLoader::load([ - 'e' => new BigInteger(\base64_decode($key->getExponent(), true), 256), - 'n' => new BigInteger($modulus, 256), - ]); - - return $rsa->__toString(); - } -} diff --git a/src/KeyFactory.php b/src/KeyFactory.php index 708ea0b..866f821 100644 --- a/src/KeyFactory.php +++ b/src/KeyFactory.php @@ -2,72 +2,92 @@ declare(strict_types=1); -namespace Strobotti\JWK; +namespace Compwright\JWKS; -use Strobotti\JWK\Key\KeyInterface; -use Strobotti\JWK\Util\Base64UrlConverter; -use Strobotti\JWK\Util\Base64UrlConverterInterface; - -/** - * @author Juha Jantunen - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ class KeyFactory { /** - * @var Base64UrlConverterInterface + * @var array */ - private $base64UrlConverter; + private array $supportedTypes = [ + Key::TYPE_RSA, + ]; /** - * KeyFactory constructor. + * @return array */ - public function __construct() + public function getSupportedTypes(): array { - $this->setBase64UrlConverter(new Base64UrlConverter()); + return $this->supportedTypes; } /** - * @since 1.0.0 - * - * @return KeyFactory + * @param string|Key::TYPE_* $kty */ - public function setBase64UrlConverter(Base64UrlConverterInterface $base64UrlConverter): self + public function supportsType(string $kty): bool { - $this->base64UrlConverter = $base64UrlConverter; - - return $this; + return in_array($kty, $this->supportedTypes); } /** - * @since 1.0.0 + * @param null|string|Key::USE_* $use */ - public function createFromPem(string $pem, array $options = []): KeyInterface + public function createFromPublicKey(string $pem, ?string $use, ?string $kid): Key { - $keyInfo = \openssl_pkey_get_details(\openssl_pkey_get_public($pem)); + $pkey = \openssl_pkey_get_public($pem); + if ($pkey === false) { + throw new \InvalidArgumentException('Error reading public key: ' . \openssl_error_string()); + } - $jsonData = \array_merge( - $options, - [ - 'kty' => 'RSA', - 'n' => $this->base64UrlConverter->encode($keyInfo['rsa']['n']), - 'e' => $this->base64UrlConverter->encode($keyInfo['rsa']['e']), - ] - ); + $keyInfo = \openssl_pkey_get_details($pkey); + if ($keyInfo === false) { + throw new \InvalidArgumentException('Error reading public key details: ' . \openssl_error_string()); + } - // TODO Only RSA is supported atm - return Key\Rsa::createFromJSON(\json_encode($jsonData)); + switch ($keyInfo['type']) { + case OPENSSL_KEYTYPE_RSA: + return new KeyTypes\RsaKey( + $use, + $kid, + Key::ALGORITHM_RS256, + Base64Url::encode($keyInfo['rsa']['n']), + Base64Url::encode($keyInfo['rsa']['e']) + ); + + default: + throw new \InvalidArgumentException('Unsupported key type', $keyInfo['type']); + } } /** - * @since 1.0.0 + * @throws \JsonException */ - public function createFromJson(string $json): KeyInterface + public function createFromJson(string $json): Key { - // TODO Only RSA is supported atm - return Key\Rsa::createFromJSON($json); + /** @var array $key */ + $key = (array) \json_decode($json, true, 512, JSON_THROW_ON_ERROR); + return $this->createFromArray($key); + } + + /** + * @param array $key + * + * @throws \InvalidArgumentException + */ + public function createFromArray(array $key): Key + { + switch ($key['kty']) { + case Key::TYPE_RSA: + return new KeyTypes\RsaKey( + $key['use'] ?? null, + $key['kid'] ?? null, + $key['alg'] ?? null, + $key['n'] ?? '', + $key['e'] ?? '' + ); + + default: + throw new \InvalidArgumentException('Unrecognized key type: ' . ($key['kty'] ?? '[missing]')); + } } } diff --git a/src/KeySet.php b/src/KeySet.php index efaf0c5..1ff2625 100644 --- a/src/KeySet.php +++ b/src/KeySet.php @@ -2,134 +2,55 @@ declare(strict_types=1); -namespace Strobotti\JWK; - -use Strobotti\JWK\Key\KeyInterface; +namespace Compwright\JWKS; /** - * @author Juha Jantunen - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 + * @implements \IteratorAggregate */ -class KeySet implements \JsonSerializable, \Countable, \IteratorAggregate +class KeySet implements \Countable, \JsonSerializable, \IteratorAggregate { /** - * @var KeyFactory - */ - private $keyFactory; - - /** - * @var KeyInterface[] - */ - private $keys = []; - - /** - * KeySet constructor. + * @param Key[] $keys */ - public function __construct() + public function __construct(protected array $keys = []) { - $this->setKeyFactory(new KeyFactory()); } - /** - * @since 1.0.0 - * - * @return false|string - */ - public function __toString() + public function __toString(): string { - return \json_encode($this->jsonSerialize(), JSON_PRETTY_PRINT); + return \json_encode($this->jsonSerialize(), JSON_THROW_ON_ERROR); } - /** - * @since 1.0.0 - */ - public function setKeyFactory(KeyFactory $keyFactory): self + public function count(): int { - $this->keyFactory = $keyFactory; - - return $this; + return \count($this->keys); } /** - * @since 1.0.0 Only $kid parameter - * @since 1.1.0 Added optional $use parameter + * @return array{keys:Key[]} */ - public function containsKey(string $kid, string $use = KeyInterface::PUBLIC_KEY_USE_SIGNATURE): bool + public function jsonSerialize(): array { - return null !== $this->getKeyById($kid, $use); + return ['keys' => $this->keys]; } /** - * @since 1.0.0 - * @since 1.1.0 Added optional $use parameter + * @return \ArrayIterator */ - public function getKeyById(string $kid, string $use = KeyInterface::PUBLIC_KEY_USE_SIGNATURE): ?KeyInterface + public function getIterator(): \ArrayIterator { - foreach ($this->getKeys() as $key) { - if ($key->getKeyId() === $kid && $key->getPublicKeyUse() === $use) { - return $key; - } - } - - return null; + return new \ArrayIterator($this->keys); } - /** - * @since 1.0.0 - * - * @return KeySet - */ - public function addKey(KeyInterface $key): self + public function addKey(Key $key): self { - if ($key->getKeyId() && $this->containsKey($key->getKeyId(), $key->getPublicKeyUse())) { - throw new \InvalidArgumentException(\sprintf('Key with id `%s` and use `%s` already exists in the set', $key->getKeyId(), $key->getPublicKeyUse())); - } - $this->keys[] = $key; - return $this; } - /** - * @return KeyInterface[] - */ - public function getKeys(): array - { - return \array_values($this->keys); - } - - /** - * @since 1.0.0 - */ - public function jsonSerialize(): array + public function getById(string $kid): ?Key { - $ret = []; - - foreach ($this->getKeys() as $key) { - $ret[$key->getKeyId()] = $key->jsonSerialize(); - } - - return [ - 'keys' => \array_values($ret), - ]; - } - - /** - * @since 1.3.0 - */ - public function count(): int - { - return \count($this->keys); - } - - /** - * @since 1.3.0 - */ - public function getIterator(): \ArrayIterator - { - return new \ArrayIterator($this->keys); + $i = array_search($kid, array_column($this->keys, 'kid'), true); + return $i === false ? null : $this->keys[$i]; } } diff --git a/src/KeySetFactory.php b/src/KeySetFactory.php index 48d51b3..719e101 100644 --- a/src/KeySetFactory.php +++ b/src/KeySetFactory.php @@ -2,59 +2,42 @@ declare(strict_types=1); -namespace Strobotti\JWK; +namespace Compwright\JWKS; -/** - * @author Juha Jantunen - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ class KeySetFactory { - /** - * @var KeyFactory - */ - private $keyFactory; - - /** - * KeySet constructor. - */ - public function __construct() + public function __construct(private KeyFactory $keyFactory) { - $this->setKeyFactory(new KeyFactory()); } /** - * @since 1.0.0 + * @throws \JsonException */ - public function setKeyFactory(KeyFactory $keyFactory): self + public function createFromJson(string $json): KeySet { - $this->keyFactory = $keyFactory; - - return $this; + $data = (array) \json_decode($json, true, 512, JSON_THROW_ON_ERROR); + /** @var array> $keys */ + $keys = $data['keys'] ?? []; + return $this->createFromArray($keys); } /** - * @since 1.0.0 + * @param array> $keys */ - public function createFromJSON(string $json): KeySet + public function createFromArray(array $keys): KeySet { - $assoc = \json_decode($json, true); - - $instance = new KeySet(); - - if (! is_array($assoc) || ! array_key_exists('keys', $assoc)) { - return $instance; - } - - foreach ($assoc['keys'] as $keyData) { - $key = $this->keyFactory->createFromJson(\json_encode($keyData)); - - $instance->addKey($key); + $set = new KeySet(); + + foreach ($keys as $key) { + try { + $set->addKey( + $this->keyFactory->createFromArray($key) + ); + } catch (\InvalidArgumentException $e) { + // skip unsupported key types + } } - return $instance; + return $set; } } diff --git a/src/KeyTypes/RsaKey.php b/src/KeyTypes/RsaKey.php new file mode 100644 index 0000000..b28bcd3 --- /dev/null +++ b/src/KeyTypes/RsaKey.php @@ -0,0 +1,42 @@ +kty = Key::TYPE_RSA; + } + + public function getPem(): string + { + $modulus = Base64Url::decode($this->n, true); + return (string) PublicKeyLoader::load([ + 'e' => new BigInteger(\base64_decode($this->e, true) ?: '', 256), + 'n' => new BigInteger($modulus, 256), + ]); + } +} diff --git a/src/Util/Base64UrlConverter.php b/src/Util/Base64UrlConverter.php deleted file mode 100644 index 9fc2ca1..0000000 --- a/src/Util/Base64UrlConverter.php +++ /dev/null @@ -1,37 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ -class Base64UrlConverter implements Base64UrlConverterInterface -{ - /** - * {@inheritdoc} - */ - public function decode(string $data, $strict = false): string - { - $b64 = \strtr($data, '-_', '+/'); - - return \base64_decode($b64, $strict); - } - - /** - * {@inheritdoc} - */ - public function encode(string $data): string - { - return \rtrim(\strtr(\base64_encode($data), '+/', '-_'), '='); - } -} diff --git a/src/Util/Base64UrlConverterInterface.php b/src/Util/Base64UrlConverterInterface.php deleted file mode 100644 index 0a9e7e5..0000000 --- a/src/Util/Base64UrlConverterInterface.php +++ /dev/null @@ -1,35 +0,0 @@ - - * @license https://opensource.org/licenses/MIT MIT - * - * @see https://github.com/Strobotti/php-jwk - * @since 1.0.0 - */ -interface Base64UrlConverterInterface -{ - /** - * Decodes Base64url formatted data to a string. - * - * @since 1.0.0 - * - * @param bool $strict - */ - public function decode(string $data, $strict = false): string; - - /** - * Encodes a string to a base64url formatted data. - * - * @since 1.0.0 - */ - public function encode(string $data): string; -} diff --git a/tests/Util/Base64UrlConverterTest.php b/tests/Base64UrlTest.php similarity index 70% rename from tests/Util/Base64UrlConverterTest.php rename to tests/Base64UrlTest.php index d653db5..17740cf 100644 --- a/tests/Util/Base64UrlConverterTest.php +++ b/tests/Base64UrlTest.php @@ -2,24 +2,21 @@ declare(strict_types=1); -namespace Strobotti\JWK\Tests\Util; +namespace Compwright\JWKS; use PHPUnit\Framework\TestCase; -use Strobotti\JWK\Util\Base64UrlConverter; /** * @internal */ -final class Base64UrlConverterTest extends TestCase +final class Base64UrlTest extends TestCase { /** * @dataProvider provideDecode */ public function testDecode(string $expected, string $input): void { - $converter = new Base64UrlConverter(); - - $this->assertSame($expected, $converter->decode($input)); + $this->assertSame($expected, Base64Url::decode($input)); } public static function provideDecode(): \Generator @@ -35,9 +32,7 @@ public static function provideDecode(): \Generator */ public function testEncode(string $expected, string $input): void { - $converter = new Base64UrlConverter(); - - static::assertSame($expected, $converter->encode($input)); + static::assertSame($expected, Base64Url::encode($input)); } public static function provideEncode(): \Generator diff --git a/tests/Key/AbstractKeyTest.php b/tests/Key/AbstractKeyTest.php deleted file mode 100644 index 5495f34..0000000 --- a/tests/Key/AbstractKeyTest.php +++ /dev/null @@ -1,57 +0,0 @@ -assertSame($json, "{$key}"); - } - - public function testSettersAndGetters(): void - { - $key = new AbstractKeyTest__AbstractKey__Mock(); - $key->setAlgorithm(KeyInterface::ALGORITHM_RS256) - ->setPublicKeyUse(KeyInterface::PUBLIC_KEY_USE_SIGNATURE) - ->setKeyType(KeyInterface::KEY_TYPE_RSA) - ->setKeyId('asdf') - ; - - $this->assertSame(KeyInterface::ALGORITHM_RS256, $key->getAlgorithm()); - $this->assertSame(KeyInterface::PUBLIC_KEY_USE_SIGNATURE, $key->getPublicKeyUse()); - $this->assertSame(KeyInterface::KEY_TYPE_RSA, $key->getKeyType()); - $this->assertSame('asdf', $key->getKeyId()); - - // Test nullable fields - $key->setKeyId(null); - $key->setPublicKeyUse(null); - - $this->assertNull($key->getKeyId()); - $this->assertNull($key->getPublicKeyUse()); - } -} - -final class AbstractKeyTest__AbstractKey__Mock extends AbstractKey -{ -} diff --git a/tests/Key/RsaTest.php b/tests/Key/RsaTest.php deleted file mode 100644 index 3168dc0..0000000 --- a/tests/Key/RsaTest.php +++ /dev/null @@ -1,86 +0,0 @@ -assertSame($expected['kty'], $key->getKeyType()); - $this->assertSame($expected['kid'], $key->getKeyId()); - $this->assertSame($expected['use'], $key->getPublicKeyUse()); - $this->assertSame($expected['alg'], $key->getAlgorithm()); - $this->assertSame($expected['n'], $key->getModulus()); - $this->assertSame($expected['e'], $key->getExponent()); - } - - public static function provideCreateFromJSON(): \Generator - { - yield [ - 'expected' => [ - 'kty' => 'RSA', - 'kid' => '86D88Kf', - 'use' => 'sig', - 'alg' => 'RS256', - 'n' => 'iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ', - 'e' => 'AQAB', - ], - 'input' => <<<'EOT' -{ - "kty": "RSA", - "kid": "86D88Kf", - "use": "sig", - "alg": "RS256", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB", - "unsupported": "ignored" -} -EOT - ]; - } - - public function testToString(): void - { - $json = <<<'EOT' -{ - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" -} -EOT; - - $key = Rsa::createFromJSON($json); - - $this->assertSame($json, "{$key}"); - } - - public function testSettersAndGetters(): void - { - $e = 'AQAB'; - $n = 'iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ'; - - $key = new Rsa(); - $key->setExponent($e) - ->setModulus($n) - ; - - $this->assertSame($e, $key->getExponent()); - $this->assertSame($n, $key->getModulus()); - } -} diff --git a/tests/KeyConverterTest.php b/tests/KeyConverterTest.php deleted file mode 100644 index c0859a3..0000000 --- a/tests/KeyConverterTest.php +++ /dev/null @@ -1,72 +0,0 @@ -assertSame( - \str_replace("\r", '', $expected), - \str_replace("\r", '', $converter->keyToPem($key)) - ); - } - - public static function provideKeyToPem(): \Generator - { - yield [ - 'key' => Rsa::createFromJSON('{ - "kty": "RSA", - "kid": "eXaunmL", - "use": "sig", - "alg": "RS256", - "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw", - "e": "AQAB" - }'), - 'expected' => <<<'EOT' ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dGQ7bQK8LgILOdLsYzf -ZjkEAoQeVC/aqyc8GC6RX7dq/KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdD -Nq1n52TpxQwI2EqxSk7I9fKPKhRt4F8+2yETlYvye+2s6NeWJim0KBtOVrk0gWvE -Dgd6WOqJl/yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X+Tip84wqwyRpU -lq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll+p/Dg8vAXxJLIJ4SNLcqgFeZe -4OfHLgdzMvxXZJnPp/VgmkcpUdRotazKZumj6dBPcXI/XID4Z4Z3OM1KrZPJNdUh -xwIDAQAB ------END PUBLIC KEY----- -EOT - ]; - } - - public function testUnsupportedKeyTypeRaisesException(): void - { - /** @var KeyInterface|MockObject $key */ - $key = $this->getMockBuilder(KeyInterface::class)->getMock(); - - $converter = new KeyConverter(); - - try { - $converter->keyToPem($key); - - $this->fail('converting an unsupported key to PEM should throw an exception'); - } catch (\InvalidArgumentException $e) { - $this->assertTrue(true); - } catch (\Throwable $e) { - $this->fail(\sprintf('converting an unsupported key to PEM threw an unexpected exception %s', \get_class($e))); - } - } -} diff --git a/tests/KeyFactoryTest.php b/tests/KeyFactoryTest.php index 32c4280..3b20200 100644 --- a/tests/KeyFactoryTest.php +++ b/tests/KeyFactoryTest.php @@ -2,58 +2,49 @@ declare(strict_types=1); -namespace Strobotti\JWK\Tests; +namespace Compwright\JWKS; use PHPUnit\Framework\TestCase; -use Strobotti\JWK\Key\Rsa; -use Strobotti\JWK\KeyFactory; -/** - * @internal - */ -final class KeyFactoryTest extends TestCase +class KeyFactoryTest extends TestCase { - /** - * @dataProvider provideCreateFromPem - */ - public function testCreateFromPem(string $pem, array $options, array $json, string $expectedInstance): void + public function testCreateFromPem(): void { $factory = new KeyFactory(); - $key = $factory->createFromPem($pem, $options); - $this->assertInstanceOf($expectedInstance, $key); - $this->assertSame($json, $key->jsonSerialize()); + $pem = file_get_contents(__DIR__ . '/key.pem') ?: ''; + $json = file_get_contents(__DIR__ . '/key.json') ?: ''; + + /** @var KeyTypes\RsaKey $key */ + $key = $factory->createFromPublicKey($pem, Key::USE_SIGNATURE, 'eXaunmL'); + + $this->assertInstanceOf(KeyTypes\RsaKey::class, $key); + $this->assertEquals(Key::ALGORITHM_RS256, $key->alg); + $this->assertEquals(Key::USE_SIGNATURE, $key->use); + $this->assertEquals('eXaunmL', $key->kid); + $this->assertEquals('4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw', $key->n); + $this->assertEquals('AQAB', $key->e); + $this->assertEquals($pem, $key->getPem()); + $this->assertSame($json, (string) $key); } - public static function provideCreateFromPem(): \Generator + public function testCreateFromJson(): void { - yield [ - 'pem' => <<<'EOT' ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dGQ7bQK8LgILOdLsYzf -ZjkEAoQeVC/aqyc8GC6RX7dq/KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdD -Nq1n52TpxQwI2EqxSk7I9fKPKhRt4F8+2yETlYvye+2s6NeWJim0KBtOVrk0gWvE -Dgd6WOqJl/yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X+Tip84wqwyRpU -lq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll+p/Dg8vAXxJLIJ4SNLcqgFeZe -4OfHLgdzMvxXZJnPp/VgmkcpUdRotazKZumj6dBPcXI/XID4Z4Z3OM1KrZPJNdUh -xwIDAQAB ------END PUBLIC KEY----- -EOT - , - 'options' => [ - 'use' => 'sig', - 'alg' => 'RS256', - 'kid' => 'eXaunmL', - ], - 'json' => [ - 'kty' => 'RSA', - 'use' => 'sig', - 'alg' => 'RS256', - 'kid' => 'eXaunmL', - 'n' => '4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw', - 'e' => 'AQAB', - ], - 'expectedInstance' => Rsa::class, - ]; + $factory = new KeyFactory(); + + $pem = file_get_contents(__DIR__ . '/key.pem') ?: ''; + $json = file_get_contents(__DIR__ . '/key.json') ?: ''; + + /** @var KeyTypes\RsaKey $key */ + $key = $factory->createFromJson($json); + + $this->assertInstanceOf(KeyTypes\RsaKey::class, $key); + $this->assertEquals(Key::ALGORITHM_RS256, $key->alg); + $this->assertEquals(Key::USE_SIGNATURE, $key->use); + $this->assertEquals('eXaunmL', $key->kid); + $this->assertEquals('4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw', $key->n); + $this->assertEquals('AQAB', $key->e); + $this->assertEquals($pem, $key->getPem()); + $this->assertSame($json, (string) $key); } } diff --git a/tests/KeySetFactoryTest.php b/tests/KeySetFactoryTest.php deleted file mode 100644 index bc25490..0000000 --- a/tests/KeySetFactoryTest.php +++ /dev/null @@ -1,67 +0,0 @@ -createFromJSON($input); - $json = $keys->jsonSerialize(); - - $this->assertSame(\json_decode($input, true), $json); - } - - public function testInvalidJsonReturnsEmptyKeySet(): void - { - $invalidJson = '{}'; - - $factory = new KeySetFactory(); - - $keySet = $factory->createFromJSON($invalidJson); - $this->assertInstanceOf(KeySet::class, $keySet); - $this->assertCount(0, $keySet); - } - - public static function provideCreateFromJSON(): \Generator - { - yield [ - 'input' => <<<'EOT' -{ - "keys": [ - { - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" - }, - { - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "eXaunmL", - "n": "4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw", - "e": "AQAB" - } - ] -} -EOT - ]; - } -} diff --git a/tests/KeySetTest.php b/tests/KeySetTest.php deleted file mode 100644 index 452b07b..0000000 --- a/tests/KeySetTest.php +++ /dev/null @@ -1,138 +0,0 @@ -assertSame($expected, "{$keySet}"); - } - - public static function provideCreateFromJSON(): \Generator - { - $keyJson = <<<'EOT' -{ - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" -} -EOT; - - yield [ - 'expected' => <<<'EOT' -{ - "keys": [ - { - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" - } - ] -} -EOT - , - 'keySet' => (new KeySet()) - ->addKey(Rsa::createFromJSON($keyJson)), - ]; - } - - public function testAddKeyThrowsErrorOnDuplicateKid(): void - { - $this->expectException(\InvalidArgumentException::class); - - $keyJson = <<<'EOT' -{ - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" -} -EOT; - $keySet = new KeySet(); - $keySet->addKey(Rsa::createFromJSON($keyJson)) - ->addKey(Rsa::createFromJSON($keyJson)) - ; - } - - public function testGetKeyById(): void - { - $keyJson = <<<'EOT' -{ - "kty": "RSA", - "use": "sig", - "alg": "RS256", - "kid": "86D88Kf", - "n": "iGaLqP6y-SJCCBq5Hv6pGDbG_SQ11MNjH7rWHcCFYz4hGwHC4lcSurTlV8u3avoVNM8jXevG1Iu1SY11qInqUvjJur--hghr1b56OPJu6H1iKulSxGjEIyDP6c5BdE1uwprYyr4IO9th8fOwCPygjLFrh44XEGbDIFeImwvBAGOhmMB2AD1n1KviyNsH0bEB7phQtiLk-ILjv1bORSRl8AK677-1T8isGfHKXGZ_ZGtStDe7Lu0Ihp8zoUt59kx2o9uWpROkzF56ypresiIl4WprClRCjz8x6cPZXU2qNWhu71TQvUFwvIvbkE1oYaJMb0jcOTmBRZA2QuYw-zHLwQ", - "e": "AQAB" -} -EOT; - - $key = Rsa::createFromJSON($keyJson); - - $keySet = new KeySet(); - $keySet->addKey($key); - - $this->assertSame($key, $keySet->getKeyById('86D88Kf')); - - $this->assertNull($keySet->getKeyById('asdf')); - } - - public function testCountable(): void - { - $keyset = new KeySet(); - $this->assertCount(0, $keyset); - - $keyset->addKey(new Rsa()); - $this->assertCount(1, $keyset); - - $keyset->addKey(new Rsa()); - $this->assertCount(2, $keyset); - } - - public function testIteratorAggregate(): void - { - $keyset = new KeySet(); - - $count = 0; - - foreach ($keyset as $key) { - ++$count; - } - - $this->assertSame(0, $count); - - $keyset->addKey(new Rsa()); - $keyset->addKey(new Rsa()); - $keyset->addKey(new Rsa()); - - foreach ($keyset as $index => $key) { - $this->assertInstanceOf(Rsa::class, $key); - $this->assertSame($index, $count); - - ++$count; - } - - $this->assertSame(3, $count); - } -} diff --git a/tests/key.json b/tests/key.json new file mode 100644 index 0000000..6dc8cb2 --- /dev/null +++ b/tests/key.json @@ -0,0 +1 @@ +{"use":"sig","kid":"eXaunmL","alg":"RS256","kty":"RSA","n":"4dGQ7bQK8LgILOdLsYzfZjkEAoQeVC_aqyc8GC6RX7dq_KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdDNq1n52TpxQwI2EqxSk7I9fKPKhRt4F8-2yETlYvye-2s6NeWJim0KBtOVrk0gWvEDgd6WOqJl_yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X-Tip84wqwyRpUlq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll-p_Dg8vAXxJLIJ4SNLcqgFeZe4OfHLgdzMvxXZJnPp_VgmkcpUdRotazKZumj6dBPcXI_XID4Z4Z3OM1KrZPJNdUhxw","e":"AQAB"} \ No newline at end of file diff --git a/tests/key.pem b/tests/key.pem new file mode 100644 index 0000000..59b8489 --- /dev/null +++ b/tests/key.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4dGQ7bQK8LgILOdLsYzf +ZjkEAoQeVC/aqyc8GC6RX7dq/KvRAQAWPvkam8VQv4GK5T4ogklEKEvj5ISBamdD +Nq1n52TpxQwI2EqxSk7I9fKPKhRt4F8+2yETlYvye+2s6NeWJim0KBtOVrk0gWvE +Dgd6WOqJl/yt5WBISvILNyVg1qAAM8JeX6dRPosahRVDjA52G2X+Tip84wqwyRpU +lq2ybzcLh3zyhCitBOebiRWDQfG26EH9lTlJhll+p/Dg8vAXxJLIJ4SNLcqgFeZe +4OfHLgdzMvxXZJnPp/VgmkcpUdRotazKZumj6dBPcXI/XID4Z4Z3OM1KrZPJNdUh +xwIDAQAB +-----END PUBLIC KEY----- \ No newline at end of file