diff --git a/.gitattributes b/.gitattributes index 6d63e560..d5d535d9 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,9 @@ * text=auto -/tests export-ignore /.gitattributes export-ignore /.gitignore export-ignore -/.travis.yml export-ignore -/phpunit.xml.dist export-ignore /.github export-ignore +/.php-cs-fixer.dist.php export-ignore +/phpstan.neon.dist export-ignore +/phpunit.xml.dist export-ignore +/tests export-ignore diff --git a/.github/actions/entrypoint.sh b/.github/actions/entrypoint.sh deleted file mode 100755 index 40402bc8..00000000 --- a/.github/actions/entrypoint.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -l - -apt-get update && \ -apt-get install -y --no-install-recommends \ - git \ - zip \ - curl \ - ca-certificates \ - unzip \ - wget - -curl --silent --show-error https://getcomposer.org/installer | php -php composer.phar self-update - -echo "---Installing dependencies ---" - -# Add compatiblity for libsodium with older versions of PHP -php composer.phar require --dev --with-dependencies paragonie/sodium_compat - -echo "---Running unit tests ---" -vendor/bin/phpunit diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 68d4f10b..fd10d13b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -38,9 +38,8 @@ jobs: php-version: "8.0" - name: Run Script run: | - composer require friendsofphp/php-cs-fixer - vendor/bin/php-cs-fixer fix --diff --dry-run . - vendor/bin/php-cs-fixer fix --rules=native_function_invocation --allow-risky=yes --diff src + composer global require friendsofphp/php-cs-fixer + ~/.composer/vendor/bin/php-cs-fixer fix --diff --dry-run --allow-risky=yes . staticanalysis: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index b22842cb..f720fb76 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ phpunit.phar.asc composer.phar composer.lock .phpunit.result.cache +.php-cs-fixer.cache diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000..fb636632 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,24 @@ +setRules([ + '@PSR2' => true, + 'concat_space' => ['spacing' => 'one'], + 'no_unused_imports' => true, + 'ordered_imports' => true, + 'new_with_braces' => true, + 'method_argument_space' => false, + 'whitespace_after_comma_in_array' => true, + 'return_type_declaration' => [ + 'space_before' => 'none' + ], + 'single_quote' => true, + 'native_function_invocation' => [ + 'strict' => false + ], + ]) + ->setFinder( + PhpCsFixer\Finder::create() + ->in(__DIR__) + ) +; diff --git a/src/JWT.php b/src/JWT.php index 7db16c4b..98a503e4 100644 --- a/src/JWT.php +++ b/src/JWT.php @@ -2,16 +2,15 @@ namespace Firebase\JWT; -use ArrayAccess; +use DateTime; use DomainException; use Exception; use InvalidArgumentException; use OpenSSLAsymmetricKey; use OpenSSLCertificate; +use stdClass; use TypeError; use UnexpectedValueException; -use DateTime; -use stdClass; /** * JSON Web Token implementation, based on this spec: @@ -111,7 +110,7 @@ public static function decode( if (null === ($payload = static::jsonDecode($payloadRaw))) { throw new UnexpectedValueException('Invalid claims encoding'); } - if (is_array($payload)) { + if (\is_array($payload)) { // prevent PHP Fatal Error in edge-cases when payload is empty array $payload = (object) $payload; } @@ -229,7 +228,7 @@ public static function sign( list($function, $algorithm) = static::$supported_algs[$alg]; switch ($function) { case 'hash_hmac': - if (!is_string($key)) { + if (!\is_string($key)) { throw new InvalidArgumentException('key must be a string when using hmac'); } return \hash_hmac($algorithm, $msg, $key, true); @@ -246,10 +245,10 @@ public static function sign( } return $signature; case 'sodium_crypto': - if (!function_exists('sodium_crypto_sign_detached')) { + if (!\function_exists('sodium_crypto_sign_detached')) { throw new DomainException('libsodium is not available'); } - if (!is_string($key)) { + if (!\is_string($key)) { throw new InvalidArgumentException('key must be a string when using EdDSA'); } try { @@ -302,10 +301,10 @@ private static function verify( 'OpenSSL error: ' . \openssl_error_string() ); case 'sodium_crypto': - if (!function_exists('sodium_crypto_sign_verify_detached')) { + if (!\function_exists('sodium_crypto_sign_verify_detached')) { throw new DomainException('libsodium is not available'); } - if (!is_string($keyMaterial)) { + if (!\is_string($keyMaterial)) { throw new InvalidArgumentException('key must be a string when using EdDSA'); } try { @@ -318,7 +317,7 @@ private static function verify( } case 'hash_hmac': default: - if (!is_string($keyMaterial)) { + if (!\is_string($keyMaterial)) { throw new InvalidArgumentException('key must be a string when using hmac'); } $hash = \hash_hmac($algorithm, $msg, $keyMaterial, true); diff --git a/src/Key.php b/src/Key.php index b09ad190..00cf7f2e 100644 --- a/src/Key.php +++ b/src/Key.php @@ -2,10 +2,10 @@ namespace Firebase\JWT; +use InvalidArgumentException; use OpenSSLAsymmetricKey; use OpenSSLCertificate; use TypeError; -use InvalidArgumentException; class Key { @@ -23,10 +23,10 @@ public function __construct( string $algorithm ) { if ( - !is_string($keyMaterial) + !\is_string($keyMaterial) && !$keyMaterial instanceof OpenSSLAsymmetricKey && !$keyMaterial instanceof OpenSSLCertificate - && !is_resource($keyMaterial) + && !\is_resource($keyMaterial) ) { throw new TypeError('Key material must be a string, resource, or OpenSSLAsymmetricKey'); } diff --git a/tests/JWKTest.php b/tests/JWKTest.php index 29d2356a..4167a2ba 100644 --- a/tests/JWKTest.php +++ b/tests/JWKTest.php @@ -2,8 +2,8 @@ namespace Firebase\JWT; -use PHPUnit\Framework\TestCase; use InvalidArgumentException; +use PHPUnit\Framework\TestCase; use UnexpectedValueException; class JWKTest extends TestCase @@ -69,7 +69,7 @@ public function testParseKeyWithEmptyDValue() $jwkSet['keys'][0]['d'] = null; $keys = JWK::parseKeySet($jwkSet); - $this->assertTrue(is_array($keys)); + $this->assertTrue(\is_array($keys)); } public function testParseJwkKeySet() @@ -79,7 +79,7 @@ public function testParseJwkKeySet() true ); $keys = JWK::parseKeySet($jwkSet); - $this->assertTrue(is_array($keys)); + $this->assertTrue(\is_array($keys)); $this->assertArrayHasKey('jwk1', $keys); self::$keys = $keys; } diff --git a/tests/JWTTest.php b/tests/JWTTest.php index 98562ca1..58c334ed 100644 --- a/tests/JWTTest.php +++ b/tests/JWTTest.php @@ -3,12 +3,12 @@ namespace Firebase\JWT; use ArrayObject; -use PHPUnit\Framework\TestCase; use DomainException; use InvalidArgumentException; +use PHPUnit\Framework\TestCase; +use stdClass; use TypeError; use UnexpectedValueException; -use stdClass; class JWTTest extends TestCase { @@ -37,7 +37,8 @@ public function testExpiredToken() $this->expectException(ExpiredException::class); $payload = [ 'message' => 'abc', - 'exp' => time() - 20]; // time in the past + 'exp' => time() - 20, // time in the past + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); JWT::decode($encoded, new Key('my_key', 'HS256')); } @@ -47,7 +48,8 @@ public function testBeforeValidTokenWithNbf() $this->expectException(BeforeValidException::class); $payload = [ 'message' => 'abc', - "nbf" => time() + 20]; // time in the future + 'nbf' => time() + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); JWT::decode($encoded, new Key('my_key', 'HS256')); } @@ -57,7 +59,8 @@ public function testBeforeValidTokenWithIat() $this->expectException(BeforeValidException::class); $payload = [ 'message' => 'abc', - "iat" => time() + 20]; // time in the future + 'iat' => time() + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); JWT::decode($encoded, new Key('my_key', 'HS256')); } @@ -66,7 +69,8 @@ public function testValidToken() { $payload = [ 'message' => 'abc', - 'exp' => time() + JWT::$leeway + 20]; // time in the future + 'exp' => time() + JWT::$leeway + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); $this->assertEquals($decoded->message, 'abc'); @@ -77,7 +81,8 @@ public function testValidTokenWithLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - 'exp' => time() - 20]; // time in the past + 'exp' => time() - 20, // time in the past + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); $this->assertEquals($decoded->message, 'abc'); @@ -89,7 +94,8 @@ public function testExpiredTokenWithLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - 'exp' => time() - 70]; // time far in the past + 'exp' => time() - 70, // time far in the past + ]; $this->expectException(ExpiredException::class); $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); @@ -101,9 +107,10 @@ public function testValidTokenWithNbf() { $payload = [ 'message' => 'abc', - "iat" => time(), + 'iat' => time(), 'exp' => time() + 20, // time in the future - "nbf" => time() - 20]; + 'nbf' => time() - 20 + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); $this->assertEquals($decoded->message, 'abc'); @@ -114,7 +121,8 @@ public function testValidTokenWithNbfLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - "nbf" => time() + 20]; // not before in near (leeway) future + 'nbf' => time() + 20, // not before in near (leeway) future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); $this->assertEquals($decoded->message, 'abc'); @@ -126,7 +134,8 @@ public function testInvalidTokenWithNbfLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - "nbf" => time() + 65]; // not before too far in future + 'nbf' => time() + 65, // not before too far in future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $this->expectException(BeforeValidException::class); JWT::decode($encoded, new Key('my_key', 'HS256')); @@ -138,7 +147,8 @@ public function testValidTokenWithIatLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - "iat" => time() + 20]; // issued in near (leeway) future + 'iat' => time() + 20, // issued in near (leeway) future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $decoded = JWT::decode($encoded, new Key('my_key', 'HS256')); $this->assertEquals($decoded->message, 'abc'); @@ -150,7 +160,8 @@ public function testInvalidTokenWithIatLeeway() JWT::$leeway = 60; $payload = [ 'message' => 'abc', - "iat" => time() + 65]; // issued too far in future + 'iat' => time() + 65, // issued too far in future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $this->expectException(BeforeValidException::class); JWT::decode($encoded, new Key('my_key', 'HS256')); @@ -161,7 +172,8 @@ public function testInvalidToken() { $payload = [ 'message' => 'abc', - 'exp' => time() + 20]; // time in the future + 'exp' => time() + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $this->expectException(SignatureInvalidException::class); JWT::decode($encoded, new Key('my_key2', 'HS256')); @@ -171,7 +183,8 @@ public function testNullKeyFails() { $payload = [ 'message' => 'abc', - 'exp' => time() + JWT::$leeway + 20]; // time in the future + 'exp' => time() + JWT::$leeway + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $this->expectException(TypeError::class); JWT::decode($encoded, new Key(null, 'HS256')); @@ -181,7 +194,8 @@ public function testEmptyKeyFails() { $payload = [ 'message' => 'abc', - 'exp' => time() + JWT::$leeway + 20]; // time in the future + 'exp' => time() + JWT::$leeway + 20, // time in the future + ]; $encoded = JWT::encode($payload, 'my_key', 'HS256'); $this->expectException(InvalidArgumentException::class); JWT::decode($encoded, new Key('', 'HS256')); @@ -250,7 +264,7 @@ public function testInvalidSegmentCount() public function testInvalidSignatureEncoding() { - $msg = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwibmFtZSI6ImZvbyJ9.Q4Kee9E8o0Xfo4ADXvYA8t7dN_X_bU9K5w6tXuiSjlUxx"; + $msg = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwibmFtZSI6ImZvbyJ9.Q4Kee9E8o0Xfo4ADXvYA8t7dN_X_bU9K5w6tXuiSjlUxx'; $this->expectException(UnexpectedValueException::class); JWT::decode($msg, new Key('secret', 'HS256')); } @@ -333,7 +347,7 @@ public function testDecodesEmptyArrayAsObject() public function testDecodesArraysInJWTAsArray() { $key = 'yma6Hq4XQegCVND8ef23OYgxSrC3IKqk'; - $payload = ['foo' => [1,2,3]]; + $payload = ['foo' => [1, 2, 3]]; $jwt = JWT::encode($payload, $key, 'HS256'); $decoded = JWT::decode($jwt, new Key($key, 'HS256')); $this->assertEquals($payload['foo'], $decoded->foo);