diff --git a/.github/workflows/php-checks.yml b/.github/workflows/php-checks.yml index 4a529d4..d3109d3 100644 --- a/.github/workflows/php-checks.yml +++ b/.github/workflows/php-checks.yml @@ -6,7 +6,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.4', '8.0', '8.1', '8.2'] + php-versions: ['8.1', '8.2', '8.3'] name: PHP ${{ matrix.php-versions }} tests steps: - name: Checkout diff --git a/CHANGELOG.md b/CHANGELOG.md index 0da4fee..6972e3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 5.0.0 + +### PHP support + +- Dropped support for PHP `8.0` and lower. +- Added support for PHP `8.3`. + ## 4.0.1 ## PHP Support diff --git a/README.md b/README.md index f3fc7cc..78ab75f 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,14 @@ [![Author](http://img.shields.io/badge/author-@angrybytes-blue.svg?style=flat-square)](https://twitter.com/angrybytes) [![Software License](https://img.shields.io/badge/license-proprietary-brightgreen.svg?style=flat-square)](LICENSE.md) -[![Build Status](https://travis-ci.org/AngryBytes/hash.svg?branch=master)](https://travis-ci.org/AngryBytes/hash) -[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/AngryBytes/hash/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AngryBytes/hash/?branch=master) +[![Build Status](https://github.com/AngryBytes/hash/actions/workflows/php-checks.yml/badge.svg?event=push) A simple PHP library that simplifies cryptographical hashing. It provides an -object oriented interface to a variety of hashing methods. +object-oriented interface to a variety of hashing methods. ## Requirements -* PHP `7.3`, `7.4` or PHP `8.0` (recommended) +* PHP `8.1`, `8.2` or PHP `8.3` (recommended) ## Installation @@ -32,7 +31,7 @@ Some of the main features of this component: ### Hashers -This library comes with a set of hashers to be utilised by this hash component (or +This library comes with a set of hashers to be utilized by this hash component (or to be used on their own): * `AngryBytes\Hash\Hasher\BlowFish` diff --git a/UPGRADING.md b/UPGRADING.md index b87d0c6..f61d302 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -6,8 +6,8 @@ This document lists important upgrade nodes and BC breaks per version. ### Update Hashing Values -If you are hashing multiple values you will need to change the way their are passed -to the hasher. Instead of passing each variable separately you will need to pass +If you are hashing multiple values, you will need to change the way they are passed +to the hasher. Instead of passing each variable separately, you will need to pass them as an array. Like so: ```php @@ -30,8 +30,8 @@ The same principle applies to `Hash::shortHash()`. ### Update Hash Validation -In the previous version hash validation would be done by creating a hash and comparing -it to the existing hash. Now, you can simple pass the value(s) to hash and the +In the previous version, hash validation would be done by creating a hash and comparing +it to the existing hash. Now, you can simply pass the value(s) to hash and the existing hash to methods: `verify()` or `verfiyShortHash()`. ```php diff --git a/composer.json b/composer.json index f5c4199..dcd9af9 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ }, "scripts": { "phpcheck": [ - "./vendor/bin/phpstan analyse -c phpstan.neon -l max --memory-limit=1G src/ tests/", + "./vendor/bin/phpstan analyse -l max --memory-limit=1G src/ tests/", "./vendor/bin/phpcs -p --standard=PSR2 --extensions=php src/ tests/" ], "phpcbf": [ @@ -35,11 +35,11 @@ ] }, "require": { - "php": "7.4.* || 8.0.* || 8.1.* || 8.2.*" + "php": "8.1.* || 8.2.* || 8.3.*" }, "require-dev": { - "phpstan/phpstan": "1.9.12", - "phpunit/phpunit": "9.5.28", - "squizlabs/php_codesniffer": "3.7.1" + "phpstan/phpstan": "1.10.46", + "phpunit/phpunit": "10.4.2", + "squizlabs/php_codesniffer": "3.7.2" } } diff --git a/phpstan.neon b/phpstan.neon deleted file mode 100644 index 45b2b41..0000000 --- a/phpstan.neon +++ /dev/null @@ -1,7 +0,0 @@ -parameters: - # @todo: Remove once we drop PHP 7.4 - reportUnmatchedIgnoredErrors: false - ignoreErrors: - - message: "#^Strict comparison using \\=\\=\\= between string and false will always evaluate to false\\.$#" - count: 1 - path: src/AngryBytes/Hash/Hasher/Password.php diff --git a/phpunit.xml b/phpunit.xml index 9145ba2..bcf8aa5 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,19 +1,12 @@ - - - - - src/ - - - + + ./tests/AngryBytes/Hash/Test - + + + src/ + + diff --git a/src/AngryBytes/Hash/HMAC.php b/src/AngryBytes/Hash/HMAC.php index 5dfe343..f9f8818 100644 --- a/src/AngryBytes/Hash/HMAC.php +++ b/src/AngryBytes/Hash/HMAC.php @@ -24,14 +24,14 @@ public function __construct(string $algorithm) */ public static function platformSupportsAlgorithm(string $algorithm): bool { - return in_array($algorithm, hash_algos()); + return in_array($algorithm, hash_algos(), true); } /** * Create an HMAC * * This method accepts multiple variables as input, but is restricted to - * strings. All input will be concatenated before hashing. + * strings. All inputs will be concatenated before hashing. * * @param string[] $args */ @@ -39,7 +39,7 @@ public function hmac(string $sharedSecret, ...$args): string { // Get the data concatenated $data = ''; - foreach ($args as $index => $arg) { + foreach ($args as $arg) { $data .= $arg; } @@ -55,7 +55,7 @@ public function hmac(string $sharedSecret, ...$args): string */ public function validHmac(string $message, string $hmac, string $sharedSecret): bool { - // Compare HMAC with received message + // Compare HMAC with a received message return Hash::compare( $hmac, // The HMAC as it should be for our shared secret diff --git a/src/AngryBytes/Hash/Hash.php b/src/AngryBytes/Hash/Hash.php index 536db9c..3be0e3a 100644 --- a/src/AngryBytes/Hash/Hash.php +++ b/src/AngryBytes/Hash/Hash.php @@ -51,10 +51,9 @@ public function getHasher(): HasherInterface /** * Generate a hash * - * @param mixed $data The data to hash. This can either be a scalar value or a serializable value. * @param mixed[] $options Additional hasher options (the actual options depend on the registered Hasher) */ - public function hash($data, array $options = []): string + public function hash(mixed $data, array $options = []): string { return $this->hasher->hash( self::getDataString($data), @@ -65,11 +64,9 @@ public function hash($data, array $options = []): string /** * Verify if the data matches the hash * - * @param mixed $data The data to verify against the hash string. - * This can either be a scalar value or a serializable value. * @param mixed[] $options */ - public function verify($data, string $hash, array $options = []): bool + public function verify(mixed $data, string $hash, array $options = []): bool { return $this->hasher->verify( self::getDataString($data), @@ -82,7 +79,7 @@ public function verify($data, string $hash, array $options = []): bool * Hash something into a short hash * * This is simply a shortened version of hash(), returning a 7 character hash, which should be good - * enough for identification purposes. Therefore it MUST NOT be used for cryptographic purposes or + * enough for identification purposes. Therefore, it MUST NOT be used for cryptographic purposes or * password storage but only to create a fast, short string to compare or identify. * * It is RECOMMENDED to only use this method with the Hasher\MD5 hasher as hashes @@ -90,10 +87,9 @@ public function verify($data, string $hash, array $options = []): bool * * @see Hash::hash() * - * @param mixed $data * @param mixed[] $options */ - public function shortHash($data, array $options = []): string + public function shortHash(mixed $data, array $options = []): string { return substr($this->hash($data, $options), 0, 7); } @@ -103,10 +99,9 @@ public function shortHash($data, array $options = []): string * * @see Hash::shortHash() * - * @param mixed $data * @param mixed[] $options */ - public function verifyShortHash($data, string $shortHash, array $options = []): bool + public function verifyShortHash(mixed $data, string $shortHash, array $options = []): bool { return self::compare( $this->shortHash($data, $options), @@ -150,10 +145,8 @@ protected function setSalt(?string $salt = null): self * Get the data as a string * * Will serialize non-scalar values - * - * @param mixed $data */ - private static function getDataString($data): string + private static function getDataString(mixed $data): string { if (is_scalar($data)) { return (string) $data; @@ -171,7 +164,7 @@ private static function getDataString($data): string * @param mixed[] $options * @return mixed[] */ - private function parseHashOptions(array $options = []) + private function parseHashOptions(array $options = []): array { $defaultOptions = []; diff --git a/src/AngryBytes/Hash/Hasher/MD5.php b/src/AngryBytes/Hash/Hasher/MD5.php index c930c9b..e77a62b 100644 --- a/src/AngryBytes/Hash/Hasher/MD5.php +++ b/src/AngryBytes/Hash/Hasher/MD5.php @@ -15,7 +15,7 @@ * This hasher MUST NOT be used for password storage. It is RECOMMENDED * to use the Hasher\Password for this purpose * - * @see AngryBytes\Hasher\Password For a password hasher + * @see Password For a password hasher */ class MD5 implements HasherInterface { @@ -24,7 +24,7 @@ class MD5 implements HasherInterface */ public function hash(string $string, array $options = []): string { - $salt = isset($options['salt']) ? $options['salt'] : ''; + $salt = $options['salt'] ?? ''; return md5($string . '-' . $salt); } diff --git a/src/AngryBytes/Hash/Hasher/Password.php b/src/AngryBytes/Hash/Hasher/Password.php index 0814997..5fc37ec 100644 --- a/src/AngryBytes/Hash/Hasher/Password.php +++ b/src/AngryBytes/Hash/Hasher/Password.php @@ -3,6 +3,9 @@ namespace AngryBytes\Hash\Hasher; use AngryBytes\Hash\HasherInterface; +use InvalidArgumentException; +use RuntimeException; +use ValueError; /** * Password Hasher Using Native PHP Hash Methods @@ -26,16 +29,19 @@ public function __construct(?int $cost = null) * {@inheritDoc} * * Supported options in $options array: - * - 'salt': Override the salt generated by password_hash() (discouraged) * - 'cost': Override the default cost (not advised) * - * @throws \RuntimeException If the hashing fails + * @throws RuntimeException If the hashing fails */ public function hash(string $data, array $options = []): string { - $hash = password_hash($data, PASSWORD_DEFAULT, $this->parsePasswordOptions($options)); - if ($hash === false) { - throw new \RuntimeException('Failed to hash password'); + try { + $hash = password_hash($data, PASSWORD_DEFAULT, $this->parsePasswordOptions($options)); + } catch (ValueError $e) { + throw new RuntimeException(sprintf( + 'Failed to hash password. An exception was thrown: %s', + $e->getMessage() + )); } return $hash; @@ -54,7 +60,7 @@ public function verify(string $string, string $hash, array $options = []): bool * * If true, the password should be rehashed after verification. * - * @param mixed[] $options Password options, @see hash() + * @param mixed[] $options Password options, @see self::hash() */ public function needsRehash(string $hash, array $options = []): bool { @@ -77,7 +83,7 @@ public function getInfo(string $hash): array * Set cost * * @param ?int $cost - * @throws \InvalidArgumentException if the cost is too high or low + * @throws InvalidArgumentException if the cost is too high or low */ public function setCost(?int $cost = null): self { @@ -88,7 +94,7 @@ public function setCost(?int $cost = null): self } if ($cost < 4 || $cost > 31) { - throw new \InvalidArgumentException(sprintf( + throw new InvalidArgumentException(sprintf( 'Cost value "%d" needs to be greater than 3 and smaller than 32', (int) $cost ));