Removed support for PHP versions older than 7.2 to add PSR-7 dependency.
This commit is contained in:
parent
da5ee82055
commit
8a179c62a4
40 changed files with 233 additions and 5446 deletions
MakefileREADME.mdcomposer.jsoncomposer.lockphpstan-legacy.neon
dev
php506
php700
php701
php802
php803
php804
src
ArrayJwkSet.phpHmacJwk.phpInvalidArgumentExceptionWithPayload.phpJwk.phpJwkSet.phpJwt.phpJwtEncoder.phpJwtValidator.phpRuntimeExceptionWithPayload.php
SecLib
UnexpectedValueExceptionWithPayload.phpUtility
Validators
NotValidBeforeValidator.phpNotValidYetException.phpTimeBasedValidator.phpTokenExpirationValidator.phpTokenExpiredException.php
WithPayload.php
13
Makefile
13
Makefile
|
@ -4,9 +4,6 @@ export ROOT
|
|||
PHPSTAN_CONFIG := $(realpath phpstan.neon)
|
||||
export PHPSTAN_CONFIG
|
||||
|
||||
PHPSTAN_LEGACY_CONFIG := $(realpath phpstan-legacy.neon)
|
||||
export PHPSTAN_LEGACY_CONFIG
|
||||
|
||||
SRC_DIR := $(realpath src)
|
||||
export SRC_DIR
|
||||
|
||||
|
@ -15,10 +12,8 @@ DEV_DIR := $(realpath dev)
|
|||
DEV_DIRS := $(wildcard ${DEV_DIR}/*)
|
||||
|
||||
# We'll use the lowest common denominator to maintain the root packages
|
||||
PHP_506 := $(shell which php5.6)
|
||||
export PHP_506
|
||||
COMPOSER_LTS := $(shell which composer-lts)
|
||||
export COMPOSER_LTS
|
||||
PHP_702 := $(shell which php7.2)
|
||||
COMPOSER := $(shell which composer)
|
||||
|
||||
SUDO = $(shell which sudo)
|
||||
|
||||
|
@ -28,10 +23,10 @@ GROUP_NAME = $(shell id -gn)
|
|||
${DEV_TARGETS}: ${DEV_DIRS}
|
||||
|
||||
install:
|
||||
${PHP_506} ${COMPOSER_LTS} install
|
||||
${PHP_702} ${COMPOSER} install
|
||||
|
||||
update:
|
||||
${PHP_506} ${COMPOSER_LTS} update
|
||||
${PHP_702} ${COMPOSER} update
|
||||
|
||||
fix-perms: # WSL skill issues
|
||||
${SUDO} chown -R ${USER_NAME}:${GROUP_NAME} .
|
||||
|
|
|
@ -4,8 +4,3 @@ This is a JWT library that exists because I ran into issues with the more common
|
|||
It is very, very loosely based on it in but you'll probably not run into many familiar things.
|
||||
|
||||
I'll write a better readme Someday...
|
||||
|
||||
## Why does this target PHP 5.6?????
|
||||
|
||||
The only core dependency this library has is PHP Sec Lib, which also targets PHP 5.6.
|
||||
Although I'm also doing it as a personal challenge to see if I can support this insane setup.
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
"homepage": "https://railgun.sh/libs/jwt",
|
||||
"license": "bsd-3-clause-clear",
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"phpseclib/phpseclib": "~3.0"
|
||||
"php": "^7.2 || ^8.0",
|
||||
"phpseclib/phpseclib": "~3.0",
|
||||
"psr/http-message": "^2.0"
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
|
|
99
composer.lock
generated
99
composer.lock
generated
|
@ -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": "69fe58fe65d92e48451e103ec91a85a2",
|
||||
"content-hash": "d7ada60109a3a64c5981029ad8ab90bc",
|
||||
"packages": [
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v1.1.0",
|
||||
"version": "v2.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/constant_time_encoding.git",
|
||||
"reference": "317718fb438e60151f72b20404f040cb5ae1d494"
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/317718fb438e60151f72b20404f040cb5ae1d494",
|
||||
"reference": "317718fb438e60151f72b20404f040cb5ae1d494",
|
||||
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"reference": "52a0d99e69f56b9ec27ace92ba56897fe6993105",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3|^7|^8"
|
||||
"php": "^7|^8"
|
||||
},
|
||||
"require-dev": {
|
||||
"paragonie/random_compat": "^1.4|^2",
|
||||
"phpunit/phpunit": ">= 4"
|
||||
"phpunit/phpunit": "^6|^7|^8|^9",
|
||||
"vimeo/psalm": "^1|^2|^3|^4"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
|
@ -71,37 +71,33 @@
|
|||
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
|
||||
"source": "https://github.com/paragonie/constant_time_encoding"
|
||||
},
|
||||
"time": "2022-01-17T05:23:46+00:00"
|
||||
"time": "2024-05-08T12:18:48+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/random_compat",
|
||||
"version": "v2.0.21",
|
||||
"version": "v9.99.100",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paragonie/random_compat.git",
|
||||
"reference": "96c132c7f2f7bc3230723b66e89f8f150b29d5ae"
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/96c132c7f2f7bc3230723b66e89f8f150b29d5ae",
|
||||
"reference": "96c132c7f2f7bc3230723b66e89f8f150b29d5ae",
|
||||
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.0"
|
||||
"php": ">= 7"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
"phpunit/phpunit": "4.*|5.*",
|
||||
"vimeo/psalm": "^1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"lib/random.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
|
@ -125,7 +121,7 @@
|
|||
"issues": "https://github.com/paragonie/random_compat/issues",
|
||||
"source": "https://github.com/paragonie/random_compat"
|
||||
},
|
||||
"time": "2022-02-16T17:07:03+00:00"
|
||||
"time": "2020-10-15T08:29:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpseclib/phpseclib",
|
||||
|
@ -236,17 +232,70 @@
|
|||
}
|
||||
],
|
||||
"time": "2024-12-14T21:12:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
"version": "2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/php-fig/http-message.git",
|
||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||
"reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Psr\\Http\\Message\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "PHP-FIG",
|
||||
"homepage": "https://www.php-fig.org/"
|
||||
}
|
||||
],
|
||||
"description": "Common interface for HTTP messages",
|
||||
"homepage": "https://github.com/php-fig/http-message",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr",
|
||||
"psr-7",
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/php-fig/http-message/tree/2.0"
|
||||
},
|
||||
"time": "2023-04-04T09:54:51+00:00"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
"php": ">=5.6"
|
||||
"php": "^7.2 || ^8.0"
|
||||
},
|
||||
"platform-dev": [],
|
||||
"plugin-api-version": "2.2.0"
|
||||
"platform-dev": {},
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
PHP_506 := $(shell which php5.6)
|
||||
COMPOSER_LTS := $(shell which composer-lts)
|
||||
VENDOR_BIN := $(realpath vendor/bin)
|
||||
|
||||
PHPUNIT = "${VENDOR_BIN}/phpunit"
|
||||
|
||||
install:
|
||||
${PHP_506} ${COMPOSER_LTS} install
|
||||
|
||||
update:
|
||||
${PHP_506} ${COMPOSER_LTS} update
|
||||
|
||||
analyze: analyse
|
||||
analyse:
|
||||
echo No static analysis available for PHP 5.6.
|
||||
|
||||
.PHONY: install update analyze analyse
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~5.7"
|
||||
}
|
||||
}
|
1550
dev/php506/composer.lock
generated
1550
dev/php506/composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,17 +0,0 @@
|
|||
PHP_700 := $(shell which php7.0)
|
||||
COMPOSER_LTS := $(shell which composer-lts)
|
||||
VENDOR_BIN := $(realpath vendor/bin)
|
||||
|
||||
PHPUNIT = "${VENDOR_BIN}/phpunit"
|
||||
|
||||
install:
|
||||
${PHP_700} ${COMPOSER_LTS} install
|
||||
|
||||
update:
|
||||
${PHP_700} ${COMPOSER_LTS} update
|
||||
|
||||
analyze: analyse
|
||||
analyse:
|
||||
echo No static analysis available for PHP 7.0.
|
||||
|
||||
.PHONY: install update analyze analyse
|
|
@ -1,5 +0,0 @@
|
|||
{
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.5"
|
||||
}
|
||||
}
|
1712
dev/php700/composer.lock
generated
1712
dev/php700/composer.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -1,22 +0,0 @@
|
|||
PHP_701 := $(shell which php7.1)
|
||||
COMPOSER_LTS := $(shell which composer-lts)
|
||||
VENDOR_BIN := $(realpath vendor/bin)
|
||||
|
||||
PHPSTAN = "${VENDOR_BIN}/phpstan"
|
||||
PHPUNIT = "${VENDOR_BIN}/phpunit"
|
||||
|
||||
ifeq ($(origin PHPSTAN_LEGACY_CONFIG),undefined)
|
||||
$(error PHPSTAN_LEGACY_CONFIG is not defined)
|
||||
endif
|
||||
|
||||
install:
|
||||
${PHP_701} ${COMPOSER_LTS} install
|
||||
|
||||
update:
|
||||
${PHP_701} ${COMPOSER_LTS} update
|
||||
|
||||
analyze: analyse
|
||||
analyse:
|
||||
${PHP_701} ${PHPSTAN} analyze -c ${PHPSTAN_LEGACY_CONFIG}
|
||||
|
||||
.PHONY: install update analyze analyse
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"require-dev": {
|
||||
"phpstan/phpstan": "^1.4",
|
||||
"phpunit/phpunit": "~7.5"
|
||||
}
|
||||
}
|
1763
dev/php701/composer.lock
generated
1763
dev/php701/composer.lock
generated
File diff suppressed because it is too large
Load diff
12
dev/php802/composer.lock
generated
12
dev/php802/composer.lock
generated
|
@ -626,16 +626,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "11.5.19",
|
||||
"version": "11.5.20",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "0da1ebcdbc4d5bd2d189cfe02846a89936d8dda5"
|
||||
"reference": "e6bdea63ecb7a8287d2cdab25bdde3126e0cfe6f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0da1ebcdbc4d5bd2d189cfe02846a89936d8dda5",
|
||||
"reference": "0da1ebcdbc4d5bd2d189cfe02846a89936d8dda5",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/e6bdea63ecb7a8287d2cdab25bdde3126e0cfe6f",
|
||||
"reference": "e6bdea63ecb7a8287d2cdab25bdde3126e0cfe6f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -707,7 +707,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.19"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.20"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -731,7 +731,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-02T06:56:52+00:00"
|
||||
"time": "2025-05-11T06:39:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
14
dev/php803/composer.lock
generated
14
dev/php803/composer.lock
generated
|
@ -637,16 +637,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "12.1.4",
|
||||
"version": "12.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "5ee57ad690bda2c487594577600931a99053436c"
|
||||
"reference": "f93ef2198df8d54b3195bcee381a33be51d8705e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5ee57ad690bda2c487594577600931a99053436c",
|
||||
"reference": "5ee57ad690bda2c487594577600931a99053436c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f93ef2198df8d54b3195bcee381a33be51d8705e",
|
||||
"reference": "f93ef2198df8d54b3195bcee381a33be51d8705e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -660,7 +660,7 @@
|
|||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.3",
|
||||
"phpunit/php-code-coverage": "^12.1.2",
|
||||
"phpunit/php-code-coverage": "^12.2.1",
|
||||
"phpunit/php-file-iterator": "^6.0.0",
|
||||
"phpunit/php-invoker": "^6.0.0",
|
||||
"phpunit/php-text-template": "^5.0.0",
|
||||
|
@ -714,7 +714,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.4"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -738,7 +738,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-02T07:01:56+00:00"
|
||||
"time": "2025-05-11T06:44:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
14
dev/php804/composer.lock
generated
14
dev/php804/composer.lock
generated
|
@ -637,16 +637,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "12.1.4",
|
||||
"version": "12.1.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "5ee57ad690bda2c487594577600931a99053436c"
|
||||
"reference": "f93ef2198df8d54b3195bcee381a33be51d8705e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/5ee57ad690bda2c487594577600931a99053436c",
|
||||
"reference": "5ee57ad690bda2c487594577600931a99053436c",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f93ef2198df8d54b3195bcee381a33be51d8705e",
|
||||
"reference": "f93ef2198df8d54b3195bcee381a33be51d8705e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -660,7 +660,7 @@
|
|||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.3",
|
||||
"phpunit/php-code-coverage": "^12.1.2",
|
||||
"phpunit/php-code-coverage": "^12.2.1",
|
||||
"phpunit/php-file-iterator": "^6.0.0",
|
||||
"phpunit/php-invoker": "^6.0.0",
|
||||
"phpunit/php-text-template": "^5.0.0",
|
||||
|
@ -714,7 +714,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.4"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.1.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -738,7 +738,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-02T07:01:56+00:00"
|
||||
"time": "2025-05-11T06:44:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
parameters:
|
||||
level: 9
|
||||
checkUninitializedProperties: true
|
||||
treatPhpDocTypesAsCertain: false
|
||||
reportUnmatchedIgnoredErrors: false
|
||||
paths:
|
||||
- src
|
||||
bootstrapFiles:
|
||||
- vendor/autoload.php
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use RuntimeException;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Represents a JSON Web Key Set backed by an array.
|
||||
|
@ -15,9 +15,7 @@ class ArrayJwkSet implements JwkSet {
|
|||
* @param array<string, Jwk> $keys
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __construct($keys) {
|
||||
if(!is_array($keys))
|
||||
throw new InvalidArgumentException('$keys must be an array');
|
||||
public function __construct(array $keys) {
|
||||
if(!array_all($keys, [self::class, 'ensureArrayType']))
|
||||
throw new InvalidArgumentException('$keys does not conform array<string, Jwk>');
|
||||
|
||||
|
@ -29,20 +27,15 @@ class ArrayJwkSet implements JwkSet {
|
|||
* @param mixed $key
|
||||
* @return bool
|
||||
*/
|
||||
private static function ensureArrayType($value, $key) {
|
||||
private static function ensureArrayType($value, $key): bool {
|
||||
return !is_string($key) || !($value instanceof Jwk);
|
||||
}
|
||||
|
||||
public function getKeys() {
|
||||
public function getKeys(): array {
|
||||
return $this->keys;
|
||||
}
|
||||
|
||||
public function getKey($keyId = null, $algo = null) {
|
||||
if($keyId !== null && !is_string($keyId))
|
||||
throw new InvalidArgumentException('$keyId must be a string or null');
|
||||
if($algo !== null && !is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string or null');
|
||||
|
||||
public function getKey(?string $keyId = null, ?string $algo = null): Jwk {
|
||||
if($keyId === null) {
|
||||
if($algo === null)
|
||||
return $this->keys[array_key_first($this->keys)];
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use RuntimeException;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Represents a HMAC JSON Web Key.
|
||||
|
@ -27,36 +27,24 @@ class HmacJwk implements Jwk {
|
|||
*/
|
||||
public function __construct(
|
||||
#[\SensitiveParameter]
|
||||
$key,
|
||||
$algo = null,
|
||||
$id = null
|
||||
string $key,
|
||||
?string $algo = null,
|
||||
?string $id = null
|
||||
) {
|
||||
if(!is_string($key))
|
||||
throw new InvalidArgumentException('$key must be a string');
|
||||
if($algo !== null && !is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string or null');
|
||||
if($id !== null && !is_string($id))
|
||||
throw new InvalidArgumentException('$id must be a string or null');
|
||||
|
||||
$this->key = $key;
|
||||
$this->algo = $algo;
|
||||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
public function getId(): ?string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getAlgorithm() {
|
||||
public function getAlgorithm(): ?string {
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
public function sign($data, $algo = null) {
|
||||
if(!is_string($data))
|
||||
throw new InvalidArgumentException('$data must be a string');
|
||||
if($algo !== null && !is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string or null');
|
||||
|
||||
public function sign(string $data, ?string $algo = null): string {
|
||||
if($algo === null) {
|
||||
if($this->algo === null)
|
||||
throw new InvalidArgumentException('this key does not specify a default algorithm, you must specify $algo');
|
||||
|
@ -74,10 +62,7 @@ class HmacJwk implements Jwk {
|
|||
return $result;
|
||||
}
|
||||
|
||||
public function verify($data, $signature, $algo = null) {
|
||||
if(!is_string($signature))
|
||||
throw new InvalidArgumentException('$signature must be a string');
|
||||
|
||||
public function verify(string $data, string $signature, ?string $algo = null): bool {
|
||||
return hash_equals($this->sign($data, $algo), $signature);
|
||||
}
|
||||
|
||||
|
@ -86,7 +71,7 @@ class HmacJwk implements Jwk {
|
|||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function algorithms() {
|
||||
public static function algorithms(): array {
|
||||
return array_keys(self::$algos);
|
||||
}
|
||||
|
||||
|
@ -97,11 +82,7 @@ class HmacJwk implements Jwk {
|
|||
* @param string $algo Native PHP algorithm.
|
||||
* @return void
|
||||
*/
|
||||
public static function defineAlgorithm($alias, $algo) {
|
||||
if(!is_string($alias))
|
||||
throw new InvalidArgumentException('$alias must be a string');
|
||||
if(!is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string');
|
||||
public static function defineAlgorithm(string $alias, string $algo): void {
|
||||
if(array_key_exists($alias, self::$algos))
|
||||
throw new InvalidArgumentException('$alias has already been defined');
|
||||
if(!in_array($algo, hash_hmac_algos()))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Provides an InvalidArgumentException with access to a JWT's payload.
|
||||
|
@ -15,18 +15,19 @@ class InvalidArgumentExceptionWithPayload extends InvalidArgumentException imple
|
|||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param string $message The Exception message to throw.
|
||||
* @param int $code The Exception code.
|
||||
* @param ?Exception $previous The previous exception used for the exception chaining.
|
||||
* Yes, this should be Throwable, but that doesn't exist in PHP 5.6.
|
||||
* @param ?Throwable $previous The previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct($payload, $message = '', $code = 0, $previous = null) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
|
||||
public function __construct(
|
||||
object $payload,
|
||||
string $message = '',
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
$this->payload = $payload;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public function getPayload() {
|
||||
public function getPayload(): object {
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
|
@ -35,15 +36,9 @@ class InvalidArgumentExceptionWithPayload extends InvalidArgumentException imple
|
|||
*
|
||||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param InvalidArgumentException $previous Exception to convert.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return InvalidArgumentExceptionWithPayload
|
||||
*/
|
||||
public static function convert($payload, $previous) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
if(!($previous instanceof InvalidArgumentException))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$previous must be InvalidArgumentException');
|
||||
|
||||
public static function convert(object $payload, InvalidArgumentException $previous) {
|
||||
return new InvalidArgumentExceptionWithPayload($payload, $previous->getMessage(), $previous->getCode(), $previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,12 +11,12 @@ interface Jwk {
|
|||
/**
|
||||
* @return ?string
|
||||
*/
|
||||
public function getId();
|
||||
public function getId(): ?string;
|
||||
|
||||
/**
|
||||
* @return ?string
|
||||
*/
|
||||
public function getAlgorithm();
|
||||
public function getAlgorithm(): ?string;
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
|
@ -25,7 +25,7 @@ interface Jwk {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return string
|
||||
*/
|
||||
public function sign($data, $algo = null);
|
||||
public function sign(string $data, ?string $algo = null): string;
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
|
@ -34,5 +34,5 @@ interface Jwk {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return bool
|
||||
*/
|
||||
public function verify($data, $signature, $algo = null);
|
||||
public function verify(string $data, string $signature, ?string $algo = null): bool;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ interface JwkSet {
|
|||
/**
|
||||
* @return array<string, Jwk>
|
||||
*/
|
||||
public function getKeys();
|
||||
public function getKeys(): array;
|
||||
|
||||
/**
|
||||
* @param ?string $keyId
|
||||
|
@ -20,5 +20,5 @@ interface JwkSet {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return Jwk
|
||||
*/
|
||||
public function getKey($keyId = null, $algo = null);
|
||||
public function getKey(?string $keyId = null, ?string $algo = null): Jwk;
|
||||
}
|
||||
|
|
22
src/Jwt.php
22
src/Jwt.php
|
@ -22,7 +22,6 @@ class Jwt {
|
|||
* @param ?string $alg Algorithm to sign the token with, must be supported by $key. If null, $key is expected to return a default value.
|
||||
* @param array<string, mixed>|object|null $headers Additional JWT header data, may not contain typ, alg or kid.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @throws UnexpectedValueException If any of the methods in $key returned unexpected values.
|
||||
* @return string
|
||||
*/
|
||||
public static function encode(
|
||||
|
@ -53,8 +52,6 @@ class Jwt {
|
|||
$algo = $key->getAlgorithm();
|
||||
if($algo === null)
|
||||
throw new InvalidArgumentException('$key did not provide a default algorithm, $alg must be specified');
|
||||
if(!is_string($algo))
|
||||
throw new UnexpectedValueException('$key->getAlgorithm() must return a string or null');
|
||||
|
||||
$headers['alg'] = $algo;
|
||||
} else {
|
||||
|
@ -65,12 +62,8 @@ class Jwt {
|
|||
}
|
||||
|
||||
$keyId = $key->getId();
|
||||
if($keyId !== null) {
|
||||
if(!is_string($keyId))
|
||||
throw new UnexpectedValueException('$key->getId() must return a string or null');
|
||||
|
||||
if($keyId !== null)
|
||||
$headers['kid'] = $keyId;
|
||||
}
|
||||
|
||||
$headers = Json::encode(array_merge($headers, $tmp));
|
||||
$payload = Json::encode($payload);
|
||||
|
@ -78,10 +71,7 @@ class Jwt {
|
|||
$encoded = sprintf('%s.%s', UriBase64::encode($headers), UriBase64::encode($payload));
|
||||
|
||||
$signature = $key->sign($encoded, $alg);
|
||||
if(!is_string($signature))
|
||||
throw new UnexpectedValueException('$key->sign() did not return a string');
|
||||
if(!empty($signature))
|
||||
$encoded = sprintf('%s.%s', $encoded, UriBase64::encode($signature));
|
||||
$encoded = sprintf('%s.%s', $encoded, UriBase64::encode($signature));
|
||||
|
||||
return $encoded;
|
||||
}
|
||||
|
@ -139,16 +129,10 @@ class Jwt {
|
|||
throw new UnexpectedValueException('$token payload part must be a JSON object');
|
||||
|
||||
$key = $keys->getKey($kid, $alg);
|
||||
if(!($key instanceof Jwk))
|
||||
throw new UnexpectedValueException('$keys->getKey() did not return an instance of Jwk');
|
||||
|
||||
$sig = UriBase64::decode($sigEnc);
|
||||
$enc = sprintf('%s.%s', $headerEnc, $payloadEnc);
|
||||
|
||||
$verify = $key->verify($enc, $sig, $alg);
|
||||
if(!is_bool($verify))
|
||||
throw new UnexpectedValueException('$key->verify() did not return a boolean');
|
||||
if(!$verify)
|
||||
if(!$key->verify($enc, $sig, $alg))
|
||||
throw new RuntimeException('could not verify signature of $token');
|
||||
|
||||
// move these to a chaining system
|
||||
|
|
|
@ -4,7 +4,6 @@ namespace Railgun\Jwt;
|
|||
use stdClass;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
use Railgun\Jwt\Utility\{UriBase64,Json};
|
||||
|
||||
/**
|
||||
|
@ -23,10 +22,8 @@ class JwtEncoder {
|
|||
*/
|
||||
public function __construct(
|
||||
JwkSet $keys,
|
||||
$validators = []
|
||||
array $validators = []
|
||||
) {
|
||||
if(!is_array($validators))
|
||||
throw new InvalidArgumentException('$validators must be an array');
|
||||
if(!array_all($validators, function($item) { return $item instanceof JwtValidator; })) // @phpstan-ignore instanceof.alwaysTrue
|
||||
throw new InvalidArgumentException('all items of $validators must implement JwtValidator');
|
||||
|
||||
|
@ -41,18 +38,9 @@ class JwtEncoder {
|
|||
* @param array<string, mixed>|object|null $headers JWT header section override.
|
||||
* @param bool $mergeHeaders Whether $headers should be merged with the actual provided headers in the token (true), or replace them entirely (false).
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @throws UnexpectedValueException If any underlying object returns unexpected data.
|
||||
* @return object Payload of the JWT.
|
||||
*/
|
||||
public function decode($token, $headers = null, $mergeHeaders = true) {
|
||||
// verify type of $token
|
||||
if(!is_string($token))
|
||||
throw new InvalidArgumentException('$token must be a string');
|
||||
|
||||
// verify type of $mergeHeaders
|
||||
if(!is_bool($mergeHeaders))
|
||||
throw new InvalidArgumentException('$mergeHeaders must be a bool');
|
||||
|
||||
public function decode(string $token, $headers = null, bool $mergeHeaders = true) {
|
||||
// verify type of $headers
|
||||
if($headers !== null) {
|
||||
if(is_object($headers))
|
||||
|
@ -93,23 +81,17 @@ class JwtEncoder {
|
|||
if(!property_exists($headers, 'alg') || !is_string($headers->alg))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$token does not contain a valid alg claim in its headers section');
|
||||
|
||||
// attempt to select the specified key
|
||||
$alg = $headers->alg;
|
||||
$kid = property_exists($headers, 'kid') && is_string($headers->kid) ? $headers->kid : null;
|
||||
|
||||
// attempt to select the specified key
|
||||
$jwk = $this->keys->getKey($kid, $alg);
|
||||
if(!($jwk instanceof Jwk))
|
||||
throw new UnexpectedValueExceptionWithPayload($payload, 'JwkSet::getKey() did not return an instance of Jwk');
|
||||
|
||||
// decode signature and reconstruct the value input
|
||||
$sig = UriBase64::decode($sigEnc);
|
||||
$enc = sprintf('%s.%s', $headersEnc, $payloadEnc);
|
||||
|
||||
// verify the signature section of $token
|
||||
$verify = $jwk->verify($enc, $sig, $alg);
|
||||
if(!is_bool($verify))
|
||||
throw new UnexpectedValueExceptionWithPayload($payload, 'Jwk::verify() did not return a boolean');
|
||||
if(!$verify)
|
||||
if(!$jwk->verify($enc, $sig, $alg))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$token could not be verified');
|
||||
|
||||
// Run validators over the headers and payload sections
|
||||
|
@ -126,7 +108,6 @@ class JwtEncoder {
|
|||
* @param array<string, mixed>|object $payload JWT payload section.
|
||||
* @param array<string, mixed>|object|null $headers JWT header section.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @throws UnexpectedValueException If any underlying object returns unexpected data.
|
||||
* @return string
|
||||
*/
|
||||
public function encode($payload, $headers = null) {
|
||||
|
@ -168,14 +149,10 @@ class JwtEncoder {
|
|||
|
||||
// attempt to select the requested key
|
||||
$jwk = $this->keys->getKey($kid, $alg);
|
||||
if(!($jwk instanceof Jwk))
|
||||
throw new UnexpectedValueException('JwkSet::getKey() did not return an instance of Jwk');
|
||||
|
||||
// check if we need to set the alg claim
|
||||
if($alg === null) {
|
||||
$alg = $jwk->getAlgorithm();
|
||||
if($alg !== null && !is_string($alg)) // @phpstan-ignore-line
|
||||
throw new UnexpectedValueException('Jwk::getAlgorithm() did not return a string or null');
|
||||
if($alg === null)
|
||||
throw new RuntimeException('Selected key does not provide a default algorithm, $headers->alg must be specified');
|
||||
|
||||
|
@ -185,8 +162,6 @@ class JwtEncoder {
|
|||
// check if we need to set the kid claim
|
||||
if($kid === null) {
|
||||
$kid = $jwk->getId();
|
||||
if($kid !== null && !is_string($kid)) // @phpstan-ignore-line
|
||||
throw new UnexpectedValueException('Jwk::getId() did not return a string or null');
|
||||
if($kid !== null)
|
||||
$headers->kid = $kid; // @phpstan-ignore-line
|
||||
}
|
||||
|
@ -204,8 +179,6 @@ class JwtEncoder {
|
|||
|
||||
// sign the token and ensure we got an expected return value
|
||||
$signature = $jwk->sign($encoded, $alg);
|
||||
if(!is_string($signature))
|
||||
throw new UnexpectedValueException('Jwk::sign() did not return a string');
|
||||
if($signature !== '')
|
||||
$signature = UriBase64::encode($signature);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use Exception;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Defines a validator for JWT decoding.
|
||||
|
@ -13,8 +13,8 @@ interface JwtValidator {
|
|||
*
|
||||
* @param object $headers Headers section from the provided JWT.
|
||||
* @param object $payload Payload section from the provided JWT.
|
||||
* @throws Exception If claims could not be validated.
|
||||
* @throws Throwable If claims could not be validated.
|
||||
* @return void
|
||||
*/
|
||||
public function validate($headers, $payload);
|
||||
public function validate(object $headers, object $payload): void;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Throwable;
|
||||
|
||||
|
@ -17,18 +15,19 @@ class RuntimeExceptionWithPayload extends RuntimeException implements WithPayloa
|
|||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param string $message The Exception message to throw.
|
||||
* @param int $code The Exception code.
|
||||
* @param ?Exception $previous The previous exception used for the exception chaining.
|
||||
* Yes, this should be Throwable, but that doesn't exist in PHP 5.6.
|
||||
* @param ?Throwable $previous The previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct($payload, $message = '', $code = 0, $previous = null) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
|
||||
public function __construct(
|
||||
object $payload,
|
||||
string $message = '',
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
$this->payload = $payload;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public function getPayload() {
|
||||
public function getPayload(): object {
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
|
@ -36,16 +35,10 @@ class RuntimeExceptionWithPayload extends RuntimeException implements WithPayloa
|
|||
* Converts a normal RuntimeException to one with a payload.
|
||||
*
|
||||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param Exception $previous Exception to convert.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @param Throwable $previous Exception to convert.
|
||||
* @return RuntimeExceptionWithPayload
|
||||
*/
|
||||
public static function convert($payload, $previous) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
if(interface_exists(Throwable::class) ? !($previous instanceof Throwable) : !($previous instanceof Exception))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$previous must be a subclass of Throwable or Exception');
|
||||
|
||||
public static function convert(object $payload, Throwable $previous) {
|
||||
return new RuntimeExceptionWithPayload($payload, $previous->getMessage(), (int)$previous->getCode(), $previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,14 +29,12 @@ class SecLibJwk implements Jwk {
|
|||
*/
|
||||
public function __construct(
|
||||
#[\SensitiveParameter]
|
||||
$key,
|
||||
AsymmetricKey $key,
|
||||
$algo = null,
|
||||
$id = null
|
||||
?string $id = null
|
||||
) {
|
||||
if(!($key instanceof AsymmetricKey) || (!($key instanceof PublicKey) && !($key instanceof PrivateKey)))
|
||||
if((!($key instanceof PublicKey) && !($key instanceof PrivateKey)))
|
||||
throw new InvalidArgumentException('$key is not a supported type combination');
|
||||
if($id !== null && !is_string($id))
|
||||
throw new InvalidArgumentException('$id must be a string or null');
|
||||
if($algo !== null) {
|
||||
if(is_string($algo))
|
||||
$algo = SecLibJwkAlgorithm::create($algo);
|
||||
|
@ -49,11 +47,11 @@ class SecLibJwk implements Jwk {
|
|||
$this->id = $id;
|
||||
}
|
||||
|
||||
public function getId() {
|
||||
public function getId(): ?string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getAlgorithm() {
|
||||
public function getAlgorithm(): ?string {
|
||||
return $this->algoInfo instanceof SecLibJwkAlgorithm
|
||||
? $this->algoInfo->getAlgorithm()
|
||||
: null;
|
||||
|
@ -64,7 +62,7 @@ class SecLibJwk implements Jwk {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return SecLibJwkAlgorithm
|
||||
*/
|
||||
private function resolveAlgo($algo) {
|
||||
private function resolveAlgo($algo): SecLibJwkAlgorithm {
|
||||
if($algo === null) {
|
||||
if($this->algoInfo === null)
|
||||
throw new InvalidArgumentException('this key does not specify a default algorithm, you must specify $algo');
|
||||
|
@ -79,15 +77,7 @@ class SecLibJwk implements Jwk {
|
|||
throw new InvalidArgumentException('$algo could not be resolved');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param SecLibJwkAlgorithm|string|null $algo
|
||||
* @throws UnexpectedValueException
|
||||
*/
|
||||
public function sign($data, $algo = null) {
|
||||
if(!is_string($data))
|
||||
throw new InvalidArgumentException('$data must be a string');
|
||||
|
||||
public function sign(string $data, ?string $algo = null): string {
|
||||
$key = $this->resolveAlgo($algo)->transform($this->key);
|
||||
if(!($key instanceof PrivateKey))
|
||||
throw new RuntimeException('this instance does not have a private key, it can only be used to verify');
|
||||
|
@ -99,16 +89,7 @@ class SecLibJwk implements Jwk {
|
|||
throw new UnexpectedValueException('unexpected return value for signature');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
* @param SecLibJwkAlgorithm|string|null $algo
|
||||
*/
|
||||
public function verify($data, $signature, $algo = null) {
|
||||
if(!is_string($data))
|
||||
throw new InvalidArgumentException('$data must be a string');
|
||||
if(!is_string($signature))
|
||||
throw new InvalidArgumentException('$signature must be a string');
|
||||
|
||||
public function verify(string $data, string $signature, ?string $algo = null): bool {
|
||||
$key = $this->resolveAlgo($algo)->transform($this->key);
|
||||
if($key instanceof PrivateKey)
|
||||
$key = $key->getPublicKey();
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
namespace Railgun\Jwt\SecLib;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
use phpseclib3\Crypt\{EC,RSA};
|
||||
use phpseclib3\Crypt\Common\AsymmetricKey;
|
||||
|
@ -24,9 +23,7 @@ class SecLibJwkAlgorithm {
|
|||
* @param string $algo
|
||||
* @param callable(AsymmetricKey): AsymmetricKey $transformFunc
|
||||
*/
|
||||
public function __construct($algo, $transformFunc) {
|
||||
if(!is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string');
|
||||
public function __construct(string $algo, $transformFunc) {
|
||||
if(!is_callable($transformFunc))
|
||||
throw new InvalidArgumentException('$transformFunc must be callable');
|
||||
|
||||
|
@ -37,7 +34,7 @@ class SecLibJwkAlgorithm {
|
|||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getAlgorithm() {
|
||||
public function getAlgorithm(): string {
|
||||
return $this->algo;
|
||||
}
|
||||
|
||||
|
@ -47,10 +44,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return AsymmetricKey
|
||||
*/
|
||||
public function transform($key) {
|
||||
if(!($key instanceof AsymmetricKey))
|
||||
throw new InvalidArgumentException('$key must be an instance of AsymmetricKey');
|
||||
|
||||
public function transform(AsymmetricKey $key): AsymmetricKey {
|
||||
$key = ($this->transformFunc)($key);
|
||||
if(!($key instanceof AsymmetricKey))
|
||||
throw new UnexpectedValueException('result of the transformer was not an AsymmetricKey');
|
||||
|
@ -63,9 +57,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return SecLibJwkAlgorithm
|
||||
*/
|
||||
public static function create($algo) {
|
||||
if(!is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string');
|
||||
public static function create(string $algo): SecLibJwkAlgorithm {
|
||||
if(!array_key_exists($algo, self::$algos))
|
||||
throw new InvalidArgumentException(sprintf('$algo is not a supported algorithm: "%s"', $algo));
|
||||
|
||||
|
@ -77,7 +69,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return RSA
|
||||
*/
|
||||
public static function ensureRsaKey($key) {
|
||||
public static function ensureRsaKey(AsymmetricKey $key): RSA {
|
||||
if($key instanceof RSA)
|
||||
return $key;
|
||||
|
||||
|
@ -89,7 +81,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function applyPkcs1Padding($key) {
|
||||
public static function applyPkcs1Padding(RSA $key): RSA {
|
||||
$key = $key->withPadding(RSA::SIGNATURE_PKCS1);
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -102,7 +94,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function applyPssPadding($key) {
|
||||
public static function applyPssPadding(RSA $key): RSA {
|
||||
$key = $key->withPadding(RSA::SIGNATURE_PSS);
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -115,7 +107,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return EC
|
||||
*/
|
||||
public static function ensureEcKey($key) {
|
||||
public static function ensureEcKey(AsymmetricKey $key): EC {
|
||||
if($key instanceof EC)
|
||||
return $key;
|
||||
|
||||
|
@ -127,7 +119,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function applyIeeeSignatureFormat($key) {
|
||||
public static function applyIeeeSignatureFormat(EC $key): EC {
|
||||
$key = $key->withSignatureFormat('IEEE');
|
||||
if(!($key instanceof EC))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -138,7 +130,7 @@ class SecLibJwkAlgorithm {
|
|||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
public static function algorithms() {
|
||||
public static function algorithms(): array {
|
||||
return array_keys(self::$algos);
|
||||
}
|
||||
|
||||
|
@ -147,7 +139,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformRs256($key) {
|
||||
public static function transformRs256(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPkcs1Padding(self::ensureRsaKey($key))->withHash('sha256');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -160,7 +152,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformRs384($key) {
|
||||
public static function transformRs384(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPkcs1Padding(self::ensureRsaKey($key))->withHash('sha384');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -173,7 +165,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformRs512($key) {
|
||||
public static function transformRs512(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPkcs1Padding(self::ensureRsaKey($key))->withHash('sha512');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -186,7 +178,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformPs256($key) {
|
||||
public static function transformPs256(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPssPadding(self::ensureRsaKey($key))->withHash('sha256');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -199,7 +191,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformPs384($key) {
|
||||
public static function transformPs384(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPssPadding(self::ensureRsaKey($key))->withHash('sha384');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -212,7 +204,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return RSA
|
||||
*/
|
||||
public static function transformPs512($key) {
|
||||
public static function transformPs512(AsymmetricKey $key): RSA {
|
||||
$key = self::applyPssPadding(self::ensureRsaKey($key))->withHash('sha512');
|
||||
if(!($key instanceof RSA))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
@ -226,7 +218,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function transformEs256($key) {
|
||||
public static function transformEs256(AsymmetricKey $key): EC {
|
||||
$key = self::ensureEcKey($key);
|
||||
if($key->getCurve() !== 'secp256r1')
|
||||
throw new InvalidArgumentException('curve must be secp256r1');
|
||||
|
@ -244,7 +236,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function transformEs256K($key) {
|
||||
public static function transformEs256K(AsymmetricKey $key): EC {
|
||||
$key = self::ensureEcKey($key);
|
||||
if($key->getCurve() !== 'secp256k1')
|
||||
throw new InvalidArgumentException('curve must be secp256k1');
|
||||
|
@ -262,7 +254,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function transformEs384($key) {
|
||||
public static function transformEs384(AsymmetricKey $key): EC {
|
||||
$key = self::ensureEcKey($key);
|
||||
if($key->getCurve() !== 'secp384r1')
|
||||
throw new InvalidArgumentException('curve must be secp384r1');
|
||||
|
@ -280,7 +272,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function transformEs512($key) {
|
||||
public static function transformEs512(AsymmetricKey $key): EC {
|
||||
$key = self::ensureEcKey($key);
|
||||
if($key->getCurve() !== 'secp521r1')
|
||||
throw new InvalidArgumentException('curve must be secp521r1');
|
||||
|
@ -298,15 +290,11 @@ class SecLibJwkAlgorithm {
|
|||
* @throws UnexpectedValueException
|
||||
* @return EC
|
||||
*/
|
||||
public static function transformEdDsa($key) {
|
||||
public static function transformEdDsa(AsymmetricKey $key): EC {
|
||||
$key = self::ensureEcKey($key);
|
||||
if($key->getCurve() !== 'Ed25519' && $key->getCurve() !== 'Ed448')
|
||||
throw new InvalidArgumentException('curve must be Ed25519 or Ed448');
|
||||
|
||||
$key = $key;
|
||||
if(!($key instanceof EC))
|
||||
throw new UnexpectedValueException('return type changed unexpectedly');
|
||||
|
||||
return $key;
|
||||
}
|
||||
|
||||
|
@ -316,9 +304,7 @@ class SecLibJwkAlgorithm {
|
|||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return void
|
||||
*/
|
||||
public static function defineAlgorithm($algo, $transformFunc) {
|
||||
if(!is_string($algo))
|
||||
throw new InvalidArgumentException('$algo must be a string');
|
||||
public static function defineAlgorithm(string $algo, $transformFunc): void {
|
||||
if(!is_callable($transformFunc))
|
||||
throw new InvalidArgumentException('$transformFunc must be a callable');
|
||||
if(array_key_exists($algo, self::$algos))
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
|
@ -16,18 +15,19 @@ class UnexpectedValueExceptionWithPayload extends UnexpectedValueException imple
|
|||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param string $message The Exception message to throw.
|
||||
* @param int $code The Exception code.
|
||||
* @param ?Exception $previous The previous exception used for the exception chaining.
|
||||
* Yes, this should be Throwable, but that doesn't exist in PHP 5.6.
|
||||
* @param ?Throwable $previous The previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct($payload, $message = '', $code = 0, $previous = null) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
|
||||
public function __construct(
|
||||
object $payload,
|
||||
string $message = '',
|
||||
int $code = 0,
|
||||
?Throwable $previous = null
|
||||
) {
|
||||
$this->payload = $payload;
|
||||
parent::__construct($message, $code, $previous);
|
||||
}
|
||||
|
||||
public function getPayload() {
|
||||
public function getPayload(): object {
|
||||
return $this->payload;
|
||||
}
|
||||
|
||||
|
@ -36,15 +36,9 @@ class UnexpectedValueExceptionWithPayload extends UnexpectedValueException imple
|
|||
*
|
||||
* @param object $payload Data that was provided for the payload section.
|
||||
* @param UnexpectedValueException $previous Exception to convert.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return UnexpectedValueExceptionWithPayload
|
||||
*/
|
||||
public static function convert($payload, $previous) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
if(!($previous instanceof UnexpectedValueException))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$previous must be UnexpectedValueException');
|
||||
|
||||
public static function convert(object $payload, UnexpectedValueException $previous): self {
|
||||
return new UnexpectedValueExceptionWithPayload($payload, $previous->getMessage(), $previous->getCode(), $previous);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt\Utility;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
use Railgun\Jwt\{InvalidArgumentExceptionWithPayload,UnexpectedValueExceptionWithPayload};
|
||||
|
@ -22,7 +20,7 @@ final class ClaimsUtils {
|
|||
* @throws UnexpectedValueException If $value could not be converted.
|
||||
* @return int
|
||||
*/
|
||||
public static function filterIntOrFloatToInt($value) {
|
||||
public static function filterIntOrFloatToInt($value): int {
|
||||
if(is_float($value))
|
||||
$value = (int)floor($value);
|
||||
elseif(!is_int($value))
|
||||
|
@ -37,15 +35,11 @@ final class ClaimsUtils {
|
|||
* @param object $payload Payload object to consider.
|
||||
* @param string[] $claims Names of the claims to check.
|
||||
* @param callable(mixed, string): mixed $filter Filter, first argument is the current value, second argument is the name of the claim, should return a cleaned version of the value or throw an exception if unacceptable.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @throws InvalidArgumentExceptionWithPayload If any of the argument types were not as expected.
|
||||
* @throws UnexpectedValueExceptionWithPayload If validation failed or any of the values do not match.
|
||||
* @return mixed
|
||||
*/
|
||||
public static function ensureIdenticalAndRetrieve($payload, $claims, $filter) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
if(!is_array($claims))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$claims must be an array of strings');
|
||||
public static function ensureIdenticalAndRetrieve(object $payload, array $claims, $filter) {
|
||||
if(!is_callable($filter))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$filter must be a callable');
|
||||
|
||||
|
@ -60,7 +54,7 @@ final class ClaimsUtils {
|
|||
// filter the value
|
||||
try {
|
||||
$value = $filter($payload->{$claim}, $claim);
|
||||
} catch(Exception $ex) {
|
||||
} catch(Throwable $ex) {
|
||||
throw ExceptionUtils::ensureWithPayload($payload, $ex);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,7 @@ final class DateTimeUtils {
|
|||
* @throws UnexpectedValueException If date/time conversion fails.
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public static function ensureImmutable($dt, $dtArg = 'dt') {
|
||||
if(!is_string($dtArg))
|
||||
throw new InvalidArgumentException('$dtArg must be a string');
|
||||
|
||||
public static function ensureImmutable($dt, string $dtArg = 'dt'): DateTimeImmutable {
|
||||
if($dt instanceof DateTimeImmutable)
|
||||
return $dt;
|
||||
|
||||
|
@ -38,8 +35,11 @@ final class DateTimeUtils {
|
|||
|
||||
if($dt instanceof DateTimeInterface) {
|
||||
// why did this not exist until PHP 8.0...
|
||||
if(method_exists(DateTimeImmutable::class, 'createFromInterface')) // @phpstan-ignore function.alreadyNarrowedType
|
||||
return DateTimeImmutable::createFromInterface($dt); // @phpstan-ignore-line
|
||||
if(method_exists(DateTimeImmutable::class, 'createFromInterface')) { // @phpstan-ignore function.alreadyNarrowedType
|
||||
$dti = DateTimeImmutable::createFromInterface($dt);
|
||||
if($dti instanceof DateTimeImmutable) // @phpstan-ignore instanceof.alwaysTrue
|
||||
return $dti;
|
||||
}
|
||||
|
||||
$dt = DateTimeImmutable::createFromFormat('Uv', $dt->format('Uv'));
|
||||
if($dt === false)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt\Utility;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
use UnexpectedValueException;
|
||||
|
@ -22,16 +21,10 @@ final class ExceptionUtils {
|
|||
* Ensures an exception includes payload data.
|
||||
*
|
||||
* @param object $payload JWT payload section.
|
||||
* @param Exception $exception Exception to potentially convert.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return Exception&WithPayload
|
||||
* @param Throwable $exception Exception to potentially convert.
|
||||
* @return Throwable&WithPayload
|
||||
*/
|
||||
public static function ensureWithPayload($payload, $exception) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
if(interface_exists(Throwable::class) ? !($exception instanceof Throwable) : !($exception instanceof Exception))
|
||||
throw new InvalidArgumentExceptionWithPayload($payload, '$exception must be a subclass of Throwable or Exception');
|
||||
|
||||
public static function ensureWithPayload(object $payload, Throwable $exception): Throwable {
|
||||
// If we already have a payload, just return immediately.
|
||||
if($exception instanceof WithPayload)
|
||||
return $exception;
|
||||
|
|
|
@ -16,7 +16,7 @@ final class Json {
|
|||
* @throws RuntimeException If there was a JSON error.
|
||||
* @return void
|
||||
*/
|
||||
private static function throwIfError() {
|
||||
private static function throwIfError(): void {
|
||||
$error = json_last_error();
|
||||
if($error !== JSON_ERROR_NONE)
|
||||
throw new RuntimeException(json_last_error_msg(), $error);
|
||||
|
@ -28,9 +28,7 @@ final class Json {
|
|||
* @param int $flags
|
||||
* @return int
|
||||
*/
|
||||
private static function applyFlags($flags) {
|
||||
if(!is_int($flags))
|
||||
$flags = 0;
|
||||
private static function applyFlags(int $flags = 0): int {
|
||||
if(defined('JSON_INVALID_UTF8_SUBSTITUTE'))
|
||||
$flags |= JSON_INVALID_UTF8_SUBSTITUTE;
|
||||
if(defined('JSON_THROW_ON_ERROR'))
|
||||
|
@ -42,16 +40,12 @@ final class Json {
|
|||
* Decodes a JSON string.
|
||||
*
|
||||
* @param string $json The json string to be decoded.
|
||||
* @throws InvalidArgumentException If any of the arguments were not of an expected type.
|
||||
* @throws RuntimeException If json value failed to decode.
|
||||
* @return mixed Returns the value encoded in json as an appropriate PHP type.
|
||||
*/
|
||||
public static function decode($json) {
|
||||
if(!is_string($json))
|
||||
throw new InvalidArgumentException('$json must be a string');
|
||||
|
||||
public static function decode(string $json) {
|
||||
try {
|
||||
$value = json_decode($json, false, 512, self::applyFlags(0));
|
||||
$value = json_decode($json, false, 512, self::applyFlags());
|
||||
} catch(\Exception $ex) {
|
||||
throw new RuntimeException($ex->getMessage(), (int)$ex->getCode(), $ex);
|
||||
}
|
||||
|
@ -70,7 +64,7 @@ final class Json {
|
|||
* @throws RuntimeException If json value failed to encode.
|
||||
* @return string Returns a JSON encoded string.
|
||||
*/
|
||||
public static function encode($value) {
|
||||
public static function encode($value): string {
|
||||
if(is_resource($value))
|
||||
throw new InvalidArgumentException('$value may not be resource');
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt\Utility;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
|
@ -14,14 +13,10 @@ final class UriBase64 {
|
|||
* Decodes a URI base64 encoded string.
|
||||
*
|
||||
* @param string $string The encoded data.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @throws UnexpectedValueException If the data could not be decoded.
|
||||
* @return string Returns the decoded data. The returned data may be binary.
|
||||
*/
|
||||
public static function decode($string) {
|
||||
if(!is_string($string))
|
||||
throw new InvalidArgumentException('$string must be a string');
|
||||
|
||||
public static function decode(string $string): string {
|
||||
$string = base64_decode(str_pad(strtr($string, '-_', '+/'), strlen($string) % 4, '=', STR_PAD_RIGHT), true);
|
||||
if($string === false)
|
||||
throw new UnexpectedValueException('$string could not be decoded');
|
||||
|
@ -33,13 +28,9 @@ final class UriBase64 {
|
|||
* Encodes the given string with URI base64.
|
||||
*
|
||||
* @param string $string The data to encode.
|
||||
* @throws InvalidArgumentException If any of the argument types were not as expected.
|
||||
* @return string The encoded data, as a string.
|
||||
*/
|
||||
public static function encode($string) {
|
||||
if(!is_string($string))
|
||||
throw new InvalidArgumentException('$string must be a string');
|
||||
|
||||
public static function encode(string $string): string {
|
||||
return rtrim(strtr(base64_encode($string), '+/', '-_'), '=');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt\Validators;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Railgun\Jwt\Utility\ClaimsUtils;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +31,11 @@ class NotValidBeforeValidator extends TimeBasedValidator {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($leeway = 0, $time = null, $claims = self::CLAIMS) {
|
||||
public function __construct(
|
||||
int $leeway = 0,
|
||||
$time = null,
|
||||
array $claims = self::CLAIMS
|
||||
) {
|
||||
parent::__construct($leeway, $time, $claims);
|
||||
}
|
||||
|
||||
|
@ -40,7 +43,7 @@ class NotValidBeforeValidator extends TimeBasedValidator {
|
|||
* {@inheritdoc}
|
||||
* @throws NotValidYetException If a token is not yet valid.
|
||||
*/
|
||||
public function validate($headers, $payload) {
|
||||
public function validate(object $headers, object $payload): void {
|
||||
// retrieve the not valid before value
|
||||
$value = ClaimsUtils::ensureIdenticalAndRetrieve($payload, $this->getClaims(), [ClaimsUtils::class, 'filterIntOrFloatToInt']);
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ class NotValidYetException extends RuntimeExceptionWithPayload {
|
|||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getValidAfter() {
|
||||
public function getValidAfter(): DateTimeImmutable {
|
||||
return $this->validAfter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,10 @@ abstract class TimeBasedValidator implements JwtValidator {
|
|||
* @param (callable(): int)|(Closure(): int)|null $time Callable that return the current timestamp, will use PHP's time() if null.
|
||||
* @param non-empty-array<string> $claims Claim names to consider as possible expiration claims, all will be ensured to be set to the same value if they are present.
|
||||
*/
|
||||
public function __construct($leeway, $time, $claims) {
|
||||
if(!is_int($leeway))
|
||||
throw new InvalidArgumentException('$leeway must be an integer');
|
||||
public function __construct(int $leeway, $time, array $claims) {
|
||||
if($time !== null && !is_callable($time))
|
||||
throw new InvalidArgumentException('$time must be null, a callable or an instance of Closure');
|
||||
if(!is_array($claims) || !array_all($claims, function($value) { return is_string($value); })) // @phpstan-ignore function.alreadyNarrowedType
|
||||
if(!array_all($claims, function($value) { return is_string($value); })) // @phpstan-ignore function.alreadyNarrowedType
|
||||
throw new InvalidArgumentException('$claims must be a non-empty array of strings');
|
||||
|
||||
$this->leeway = $leeway;
|
||||
|
@ -41,7 +39,7 @@ abstract class TimeBasedValidator implements JwtValidator {
|
|||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getLeeway() {
|
||||
protected function getLeeway(): int {
|
||||
return $this->leeway;
|
||||
}
|
||||
|
||||
|
@ -50,7 +48,7 @@ abstract class TimeBasedValidator implements JwtValidator {
|
|||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getTime() {
|
||||
protected function getTime(): int {
|
||||
return ($this->time)();
|
||||
}
|
||||
|
||||
|
@ -59,9 +57,9 @@ abstract class TimeBasedValidator implements JwtValidator {
|
|||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function getClaims() {
|
||||
protected function getClaims(): array {
|
||||
return $this->claims;
|
||||
}
|
||||
|
||||
abstract public function validate($headers, $payload);
|
||||
abstract public function validate(object $headers, object $payload): void;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
namespace Railgun\Jwt\Validators;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use Railgun\Jwt\Utility\ClaimsUtils;
|
||||
|
||||
/**
|
||||
|
@ -25,7 +24,11 @@ class TokenExpirationValidator extends TimeBasedValidator {
|
|||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __construct($leeway = 0, $time = null, $claims = self::CLAIMS) {
|
||||
public function __construct(
|
||||
int $leeway = 0,
|
||||
$time = null,
|
||||
array $claims = self::CLAIMS
|
||||
) {
|
||||
parent::__construct($leeway, $time, $claims);
|
||||
}
|
||||
|
||||
|
@ -33,7 +36,7 @@ class TokenExpirationValidator extends TimeBasedValidator {
|
|||
* {@inheritdoc}
|
||||
* @throws TokenExpiredException If a token has expired.
|
||||
*/
|
||||
public function validate($headers, $payload) {
|
||||
public function validate(object $headers, object $payload): void {
|
||||
// retrieve the expiration value
|
||||
$value = ClaimsUtils::ensureIdenticalAndRetrieve($payload, $this->getClaims(), [ClaimsUtils::class, 'filterIntOrFloatToInt']);
|
||||
|
||||
|
|
|
@ -19,9 +19,6 @@ class TokenExpiredException extends RuntimeExceptionWithPayload {
|
|||
* @param DateTimeInterface|int $expiredAt Expiration time.
|
||||
*/
|
||||
public function __construct($payload, $expiredAt) {
|
||||
if(!is_object($payload))
|
||||
throw new InvalidArgumentException('$payload must be an object');
|
||||
|
||||
try {
|
||||
$this->expiredAt = DateTimeUtils::ensureImmutable($expiredAt, 'expiredAt');
|
||||
} catch(InvalidArgumentException $ex) {
|
||||
|
@ -36,7 +33,7 @@ class TokenExpiredException extends RuntimeExceptionWithPayload {
|
|||
*
|
||||
* @return DateTimeImmutable
|
||||
*/
|
||||
public function getExpiredAt() {
|
||||
public function getExpiredAt(): DateTimeImmutable {
|
||||
return $this->expiredAt;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,5 +10,5 @@ interface WithPayload {
|
|||
*
|
||||
* @return object
|
||||
*/
|
||||
public function getPayload();
|
||||
public function getPayload(): object;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue