diff --git a/.github/workflows/deptrac.yml b/.github/workflows/deptrac.yml index ebaf4df1e..f4817721a 100644 --- a/.github/workflows/deptrac.yml +++ b/.github/workflows/deptrac.yml @@ -20,4 +20,4 @@ on: jobs: deptrac: - uses: codeigniter4/.github/.github/workflows/deptrac.yml@main + uses: codeigniter4/.github/.github/workflows/deptrac.yml@CI46 diff --git a/.github/workflows/phpcpd.yml b/.github/workflows/phpcpd.yml index 2704b80fc..cf1bdedab 100644 --- a/.github/workflows/phpcpd.yml +++ b/.github/workflows/phpcpd.yml @@ -16,7 +16,7 @@ on: jobs: phpcpd: - uses: codeigniter4/.github/.github/workflows/phpcpd.yml@main + uses: codeigniter4/.github/.github/workflows/phpcpd.yml@CI46 with: dirs: "src/ tests/" options: "--exclude src/Database/Migrations/2020-12-28-223112_create_auth_tables.php --exclude src/Authentication/Authenticators/HmacSha256.php --exclude tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php" diff --git a/.github/workflows/phpcsfixer.yml b/.github/workflows/phpcsfixer.yml index ee1221ac2..773c0dc54 100644 --- a/.github/workflows/phpcsfixer.yml +++ b/.github/workflows/phpcsfixer.yml @@ -16,4 +16,4 @@ on: jobs: phpcsfixer: - uses: codeigniter4/.github/.github/workflows/phpcsfixer.yml@main + uses: codeigniter4/.github/.github/workflows/phpcsfixer.yml@CI46 diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 58e2add51..01d9b3685 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -20,4 +20,4 @@ on: jobs: phpstan: - uses: codeigniter4/.github/.github/workflows/phpstan.yml@main + uses: codeigniter4/.github/.github/workflows/phpstan.yml@CI46 diff --git a/.github/workflows/phpunit-lang.yml b/.github/workflows/phpunit-lang.yml index 0a89cbcd9..14dbca738 100644 --- a/.github/workflows/phpunit-lang.yml +++ b/.github/workflows/phpunit-lang.yml @@ -59,7 +59,7 @@ jobs: fi - name: Test with PHPUnit - run: vendor/bin/phpunit --verbose --no-coverage --testsuite lang + run: vendor/bin/phpunit --no-coverage --testsuite lang env: TERM: xterm-256color TACHYCARDIA_MONITOR_GA: enabled diff --git a/.github/workflows/phpunit-lowest.yml b/.github/workflows/phpunit-lowest.yml index 242a89803..f9a81c74e 100644 --- a/.github/workflows/phpunit-lowest.yml +++ b/.github/workflows/phpunit-lowest.yml @@ -20,4 +20,4 @@ on: jobs: phpunit: - uses: codeigniter4/.github/.github/workflows/phpunit-lowest.yml@main + uses: codeigniter4/.github/.github/workflows/phpunit-lowest.yml@CI46 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 9bcd5ec40..68b9dbcbf 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -20,4 +20,4 @@ on: jobs: phpunit: - uses: codeigniter4/.github/.github/workflows/phpunit.yml@main + uses: codeigniter4/.github/.github/workflows/phpunit.yml@CI46 diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 53c76e7f9..cf704fd8f 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -20,4 +20,4 @@ on: jobs: psalm: - uses: codeigniter4/.github/.github/workflows/psalm.yml@main + uses: codeigniter4/.github/.github/workflows/psalm.yml@CI46 diff --git a/.github/workflows/rector.yml b/.github/workflows/rector.yml index 8c19b162d..9a6044728 100644 --- a/.github/workflows/rector.yml +++ b/.github/workflows/rector.yml @@ -20,4 +20,4 @@ on: jobs: rector: - uses: codeigniter4/.github/.github/workflows/rector.yml@main + uses: codeigniter4/.github/.github/workflows/rector.yml@CI46 diff --git a/.github/workflows/unused.yml b/.github/workflows/unused.yml index 1758dda62..5695e9043 100644 --- a/.github/workflows/unused.yml +++ b/.github/workflows/unused.yml @@ -18,4 +18,4 @@ on: jobs: unused: - uses: codeigniter4/.github/.github/workflows/unused.yml@main + uses: codeigniter4/.github/.github/workflows/unused.yml@CI46 diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 2979b15aa..ebcd908ad 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -41,5 +41,5 @@ return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary( 'CodeIgniter Shield', 'CodeIgniter Foundation', - 'admin@codeigniter.com' + 'admin@codeigniter.com', ); diff --git a/README.md b/README.md index b6f93e9a4..5d10c9f31 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Usage of Shield requires the following: - A [CodeIgniter 4.3.5+](https://github.com/codeigniter4/CodeIgniter4/) based project - [Composer](https://getcomposer.org/) for package management -- PHP 7.4.3+ +- PHP 8.1+ ### Installation diff --git a/composer.json b/composer.json index c776fb168..38de6c14c 100644 --- a/composer.json +++ b/composer.json @@ -25,21 +25,17 @@ "slack": "https://codeigniterchat.slack.com" }, "require": { - "php": "^7.4.3 || ^8.0", + "php": "^8.1", "codeigniter4/settings": "^2.1" }, "require-dev": { - "codeigniter/coding-standard": "1.7.*", "codeigniter/phpstan-codeigniter": "^1.3", - "codeigniter4/devkit": "^1.0", + "codeigniter4/devkit": "^1.3", "codeigniter4/framework": ">=4.3.5 <4.5.0 || ^4.5.1", "firebase/php-jwt": "^6.4", "mikey179/vfsstream": "^1.6.7", "mockery/mockery": "^1.0", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan-strict-rules": "^1.5", - "phpunit/phpunit": "^9.6", - "rector/rector": "1.2.10" + "phpstan/phpstan-strict-rules": "^2.0" }, "provide": { "codeigniter4/authentication-implementation": "1.0" diff --git a/docs/getting_started/install.md b/docs/getting_started/install.md index 2f9534e3f..bcc87c9a8 100644 --- a/docs/getting_started/install.md +++ b/docs/getting_started/install.md @@ -4,6 +4,7 @@ These instructions assume that you have already [installed the CodeIgniter 4 app ## Requirements +- PHP 8.1+ - [Composer](https://getcomposer.org) - Codeigniter **v4.3.5** or later - A created database that you can access via the Spark CLI script diff --git a/phpstan-baseline.php b/phpstan-baseline.php index 94be2606f..575162eb4 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -2,403 +2,499 @@ $ignoreErrors = []; $ignoreErrors[] = [ - // identifier: function.deprecated 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', + 'identifier' => 'function.deprecated', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 2, 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; $ignoreErrors[] = [ - // identifier: function.deprecated 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', + 'identifier' => 'function.deprecated', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Actions/EmailActivator.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 2, 'path' => __DIR__ . '/src/Authentication/Actions/EmailActivator.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authentication.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 2, 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', ]; $ignoreErrors[] = [ - // identifier: booleanAnd.leftNotBoolean 'message' => '#^Only booleans are allowed in &&, CodeIgniter\\\\I18n\\\\Time\\|null given on the left side\\.$#', + 'identifier' => 'booleanAnd.leftNotBoolean', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType 'message' => '#^Parameter \\#1 \\$credentials \\(array\\{token\\?\\: string\\}\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\Authenticators\\\\JWT\\:\\:attempt\\(\\) should be contravariant with parameter \\$credentials \\(array\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\AuthenticatorInterface\\:\\:attempt\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType 'message' => '#^Parameter \\#1 \\$credentials \\(array\\{token\\?\\: string\\}\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\Authenticators\\\\JWT\\:\\:check\\(\\) should be contravariant with parameter \\$credentials \\(array\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\AuthenticatorInterface\\:\\:check\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\RememberModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: if.condNotBoolean 'message' => '#^Only booleans are allowed in an if condition, int\\|string\\|null given\\.$#', + 'identifier' => 'if.condNotBoolean', 'count' => 3, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType 'message' => '#^Parameter \\#1 \\$credentials \\(array\\{email\\?\\: string, username\\?\\: string, password\\?\\: string\\}\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\Authenticators\\\\Session\\:\\:attempt\\(\\) should be contravariant with parameter \\$credentials \\(array\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\AuthenticatorInterface\\:\\:attempt\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType 'message' => '#^Parameter \\#1 \\$credentials \\(array\\{email\\?\\: string, username\\?\\: string, password\\?\\: string\\}\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\Authenticators\\\\Session\\:\\:check\\(\\) should be contravariant with parameter \\$credentials \\(array\\) of method CodeIgniter\\\\Shield\\\\Authentication\\\\AuthenticatorInterface\\:\\:check\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 4, 'path' => __DIR__ . '/src/Authentication/Passwords/NothingPersonalValidator.php', ]; $ignoreErrors[] = [ - // identifier: booleanAnd.rightNotBoolean + 'message' => '#^PHPDoc tag @var with type string is not subtype of type uppercase\\-string\\.$#', + 'identifier' => 'varTag.type', + 'count' => 1, + 'path' => __DIR__ . '/src/Authentication/Passwords/PwnedValidator.php', +]; +$ignoreErrors[] = [ 'message' => '#^Only booleans are allowed in &&, CodeIgniter\\\\Shield\\\\Entities\\\\User\\|null given on the right side\\.$#', + 'identifier' => 'booleanAnd.rightNotBoolean', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Passwords/ValidationRules.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 3, 'path' => __DIR__ . '/src/Authorization/Groups.php', ]; $ignoreErrors[] = [ - // identifier: method.childReturnType 'message' => '#^Return type \\(int\\|string\\|null\\) of method CodeIgniter\\\\Shield\\\\Collectors\\\\Auth\\:\\:getBadgeValue\\(\\) should be covariant with return type \\(int\\|null\\) of method CodeIgniter\\\\Debug\\\\Toolbar\\\\Collectors\\\\BaseCollector\\:\\:getBadgeValue\\(\\)$#', + 'identifier' => 'method.childReturnType', 'count' => 1, 'path' => __DIR__ . '/src/Collectors/Auth.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch + 'message' => '#^Cannot access property \\$id on array\\\\|object\\.$#', + 'identifier' => 'property.nonObject', + 'count' => 7, + 'path' => __DIR__ . '/src/Commands/Hmac.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Cannot access property \\$secret2 on array\\\\|object\\.$#', + 'identifier' => 'property.nonObject', + 'count' => 11, + 'path' => __DIR__ . '/src/Commands/Hmac.php', +]; +$ignoreErrors[] = [ 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Commands/User.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 9, 'path' => __DIR__ . '/src/Commands/User.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Controllers/ActionController.php', -]; -$ignoreErrors[] = [ - // identifier: instanceof.alwaysTrue - 'message' => '#^Instanceof between CodeIgniter\\\\Shield\\\\Authentication\\\\Actions\\\\ActionInterface and CodeIgniter\\\\Shield\\\\Authentication\\\\Actions\\\\ActionInterface will always evaluate to true\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Controllers/ActionController.php', -]; -$ignoreErrors[] = [ - // identifier: function.deprecated 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', + 'identifier' => 'function.deprecated', 'count' => 1, 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 2, 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ - // identifier: function.impossibleType 'message' => '#^Call to function assert\\(\\) with false and \'Config Auth…\' will always evaluate to false\\.$#', + 'identifier' => 'function.impossibleType', 'count' => 1, 'path' => __DIR__ . '/src/Controllers/RegisterController.php', ]; $ignoreErrors[] = [ - // identifier: instanceof.alwaysFalse 'message' => '#^Instanceof between null and CodeIgniter\\\\Shield\\\\Models\\\\UserModel will always evaluate to false\\.$#', + 'identifier' => 'instanceof.alwaysFalse', 'count' => 1, 'path' => __DIR__ . '/src/Controllers/RegisterController.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.modelArgumentType 'message' => '#^Parameter \\#1 \\$name of function model expects a valid class string, array\\|bool\\|float\\|int\\|object\\|string\\|null given\\.$#', + 'identifier' => 'codeigniter.modelArgumentType', 'count' => 1, 'path' => __DIR__ . '/src/Controllers/RegisterController.php', ]; $ignoreErrors[] = [ - // identifier: method.notFound 'message' => '#^Call to an undefined method CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:disableForeignKeyChecks\\(\\)\\.$#', + 'identifier' => 'method.notFound', 'count' => 1, 'path' => __DIR__ . '/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php', ]; $ignoreErrors[] = [ - // identifier: method.notFound 'message' => '#^Call to an undefined method CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:enableForeignKeyChecks\\(\\)\\.$#', + 'identifier' => 'method.notFound', 'count' => 1, 'path' => __DIR__ . '/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 4, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 2, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\PermissionModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 2, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 19, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 7, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: ternary.condNotBoolean 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, max\\> given\\.$#', + 'identifier' => 'ternary.condNotBoolean', 'count' => 1, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/AbstractAuthFilter.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\AbstractAuthFilter\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/AbstractAuthFilter.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\AbstractAuthFilter\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', 'count' => 1, 'path' => __DIR__ . '/src/Filters/AbstractAuthFilter.php', ]; $ignoreErrors[] = [ - // identifier: return.type 'message' => '#^Method CodeIgniter\\\\Shield\\\\Filters\\\\AuthRates\\:\\:before\\(\\) should return CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void but returns CodeIgniter\\\\HTTP\\\\ResponseInterface\\.$#', + 'identifier' => 'return.type', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/AuthRates.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\AuthRates\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/AuthRates.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\AuthRates\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', 'count' => 1, 'path' => __DIR__ . '/src/Filters/AuthRates.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\ChainAuth\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/ChainAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\ChainAuth\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/ChainAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\ForcePasswordResetFilter\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/ForcePasswordResetFilter.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\ForcePasswordResetFilter\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/ForcePasswordResetFilter.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\HmacAuth\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/HmacAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\JWTAuth\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/JWTAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\JWTAuth\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/JWTAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\SessionAuth\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/SessionAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\SessionAuth\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/SessionAuth.php', +]; +$ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 1, 'path' => __DIR__ . '/src/Filters/TokenAuth.php', ]; $ignoreErrors[] = [ - // identifier: return.type 'message' => '#^Method CodeIgniter\\\\Shield\\\\Filters\\\\TokenAuth\\:\\:before\\(\\) should return CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void but returns CodeIgniter\\\\HTTP\\\\ResponseInterface\\.$#', + 'identifier' => 'return.type', 'count' => 2, 'path' => __DIR__ . '/src/Filters/TokenAuth.php', ]; $ignoreErrors[] = [ - // identifier: function.deprecated + 'message' => '#^Return type \\(CodeIgniter\\\\HTTP\\\\RedirectResponse\\|void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\TokenAuth\\:\\:before\\(\\) should be covariant with return type \\(CodeIgniter\\\\HTTP\\\\RequestInterface\\|CodeIgniter\\\\HTTP\\\\ResponseInterface\\|string\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:before\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/TokenAuth.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Return type \\(void\\) of method CodeIgniter\\\\Shield\\\\Filters\\\\TokenAuth\\:\\:after\\(\\) should be compatible with return type \\(CodeIgniter\\\\HTTP\\\\ResponseInterface\\|null\\) of method CodeIgniter\\\\Filters\\\\FilterInterface\\:\\:after\\(\\)$#', + 'identifier' => 'method.childReturnType', + 'count' => 1, + 'path' => __DIR__ . '/src/Filters/TokenAuth.php', +]; +$ignoreErrors[] = [ 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', + 'identifier' => 'function.deprecated', 'count' => 1, 'path' => __DIR__ . '/src/Models/TokenLoginModel.php', ]; $ignoreErrors[] = [ - // identifier: function.deprecated 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', + 'identifier' => 'function.deprecated', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserIdentityModel.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: codeigniter.factoriesClassConstFetch 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'identifier' => 'codeigniter.factoriesClassConstFetch', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: empty.notAllowed 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'identifier' => 'empty.notAllowed', 'count' => 2, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType - 'message' => '#^Parameter \\#1 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:insert\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\|null\\) of method CodeIgniter\\\\Model\\:\\:insert\\(\\)$#', + 'message' => '#^Parameter \\#1 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:insert\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\|null\\) of method CodeIgniter\\\\Model\\:\\:insert\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType - 'message' => '#^Parameter \\#1 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:save\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\) of method CodeIgniter\\\\BaseModel\\:\\:save\\(\\)$#', + 'message' => '#^Parameter \\#1 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:save\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\) of method CodeIgniter\\\\BaseModel\\:\\:save\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: method.childParameterType - 'message' => '#^Parameter \\#2 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:update\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\|null\\) of method CodeIgniter\\\\Model\\:\\:update\\(\\)$#', + 'message' => '#^Parameter \\#2 \\$row \\(array\\|CodeIgniter\\\\Shield\\\\Entities\\\\User\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:update\\(\\) should be contravariant with parameter \\$row \\(array\\\\|object\\|null\\) of method CodeIgniter\\\\Model\\:\\:update\\(\\)$#', + 'identifier' => 'method.childParameterType', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: method.childReturnType 'message' => '#^Return type \\(int\\|string\\|true\\) of method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:insert\\(\\) should be covariant with return type \\(\\(\\$returnID is true \\? int\\|string\\|false \\: bool\\)\\) of method CodeIgniter\\\\Model\\:\\:insert\\(\\)$#', + 'identifier' => 'method.childReturnType', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - // identifier: method.alreadyNarrowedType 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Result\' and CodeIgniter\\\\Shield\\\\Result will always evaluate to true\\.$#', + 'identifier' => 'method.alreadyNarrowedType', 'count' => 3, 'path' => __DIR__ . '/tests/Authentication/Authenticators/JWTAuthenticatorTest.php', ]; $ignoreErrors[] = [ - // identifier: method.alreadyNarrowedType 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Result\' and CodeIgniter\\\\Shield\\\\Result will always evaluate to true\\.$#', + 'identifier' => 'method.alreadyNarrowedType', 'count' => 8, 'path' => __DIR__ . '/tests/Authentication/Authenticators/SessionAuthenticatorTest.php', ]; $ignoreErrors[] = [ - // identifier: variable.implicitArray 'message' => '#^Implicit array creation is not allowed \\- variable \\$users might not exist\\.$#', + 'identifier' => 'variable.implicitArray', 'count' => 1, 'path' => __DIR__ . '/tests/Authentication/ForcePasswordResetTest.php', ]; $ignoreErrors[] = [ - // identifier: variable.undefined 'message' => '#^Variable \\$users might not be defined\\.$#', + 'identifier' => 'variable.undefined', 'count' => 1, 'path' => __DIR__ . '/tests/Authentication/ForcePasswordResetTest.php', ]; $ignoreErrors[] = [ - // identifier: method.alreadyNarrowedType 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Entities\\\\\\\\AccessToken\' and CodeIgniter\\\\Shield\\\\Entities\\\\AccessToken will always evaluate to true\\.$#', + 'identifier' => 'method.alreadyNarrowedType', 'count' => 1, 'path' => __DIR__ . '/tests/Authentication/HasAccessTokensTest.php', ]; $ignoreErrors[] = [ - // identifier: ternary.condNotBoolean 'message' => '#^Only booleans are allowed in a ternary operator condition, string\\|null given\\.$#', + 'identifier' => 'ternary.condNotBoolean', 'count' => 2, 'path' => __DIR__ . '/tests/Language/AbstractTranslationTestCase.php', ]; $ignoreErrors[] = [ - // identifier: method.alreadyNarrowedType 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertIsString\\(\\) with string will always evaluate to true\\.$#', + 'identifier' => 'method.alreadyNarrowedType', 'count' => 6, 'path' => __DIR__ . '/tests/Unit/Authentication/JWT/JWTManagerTest.php', ]; $ignoreErrors[] = [ - // identifier: method.notFound 'message' => '#^Call to an undefined method CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:getLastQuery\\(\\)\\.$#', + 'identifier' => 'method.notFound', 'count' => 1, 'path' => __DIR__ . '/tests/Unit/UserTest.php', ]; $ignoreErrors[] = [ - // identifier: method.alreadyNarrowedType 'message' => '#^Call to method PHPUnit\\\\Framework\\\\Assert\\:\\:assertInstanceOf\\(\\) with \'CodeIgniter\\\\\\\\Shield\\\\\\\\Entities\\\\\\\\UserIdentity\' and CodeIgniter\\\\Shield\\\\Entities\\\\UserIdentity will always evaluate to true\\.$#', + 'identifier' => 'method.alreadyNarrowedType', 'count' => 1, 'path' => __DIR__ . '/tests/Unit/UserTest.php', ]; diff --git a/phpstan.neon.dist b/phpstan.neon.dist index eabfd9204..c878a54a5 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -29,5 +29,8 @@ parameters: allRules: false disallowedLooseComparison: true booleansInConditions: true - disallowedConstructs: true + disallowedBacktick: true + disallowedEmpty: true + disallowedImplicitArrayCreation: true + disallowedShortTernary: true matchingInheritedMethodNames: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index b25b4ca2a..4d82a9068 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,112 +1,79 @@ - - - - ./src/ - - - ./src/Config - ./src/Views - ./src/Language - - - - - - - - - - - - - ./tests - ./tests/Language - - - ./tests/Language - - - - - - - - - 0.50 - - - 30 - - - 2 - - - true - - - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.5/phpunit.xsd" + bootstrap="vendor/codeigniter4/framework/system/Test/bootstrap.php" + backupGlobals="false" + beStrictAboutOutputDuringTests="true" + colors="true" + executionOrder="random" + failOnRisky="true" + failOnWarning="true" + stopOnError="false" + stopOnFailure="false" + stopOnIncomplete="false" + stopOnSkipped="false" + cacheDirectory="build/.phpunit.cache" + beStrictAboutCoverageMetadata="true"> + + + + + + + + + + + + ./tests + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + ./src/ + + + ./src/Config + ./src/Views + ./src/Language + + diff --git a/rector.php b/rector.php index 8185f4a71..9f003517e 100644 --- a/rector.php +++ b/rector.php @@ -44,6 +44,7 @@ use Rector\EarlyReturn\Rector\Return_\PreparedValueToEarlyReturnRector; use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; +use Rector\Php81\Rector\ClassMethod\NewInInitializerRector; use Rector\PHPUnit\AnnotationsToAttributes\Rector\Class_\AnnotationWithValueToAttributeRector; use Rector\PHPUnit\CodeQuality\Rector\Class_\YieldDataProviderRector; use Rector\PHPUnit\Set\PHPUnitSetList; @@ -58,7 +59,7 @@ return static function (RectorConfig $rectorConfig): void { $rectorConfig->sets([ SetList::DEAD_CODE, - LevelSetList::UP_TO_PHP_74, + LevelSetList::UP_TO_PHP_81, PHPUnitSetList::PHPUNIT_CODE_QUALITY, PHPUnitSetList::PHPUNIT_100, ]); @@ -94,7 +95,7 @@ ]); // Set the target version for refactoring - $rectorConfig->phpVersion(PhpVersion::PHP_74); + $rectorConfig->phpVersion(PhpVersion::PHP_81); // Auto-import fully qualified class names $rectorConfig->importNames(); @@ -131,6 +132,13 @@ // To check old Email Config file __DIR__ . '/src/Commands/Setup.php', ], + + // Ignore for some existing classes to prevent BC break + NewInInitializerRector::class => [ + __DIR__ . '/src/Authentication/JWT/JWSEncoder.php', + __DIR__ . '/src/Authentication/JWT/JWSDecoder.php', + __DIR__ . '/src/Authentication/JWTManager.php', + ], ]); // auto import fully qualified class names diff --git a/src/Auth.php b/src/Auth.php index d1b000e35..be454bf86 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -43,7 +43,6 @@ class Auth */ public const SHIELD_VERSION = '1.1.0'; - protected AuthConfig $config; protected ?Authentication $authenticate = null; /** @@ -53,9 +52,8 @@ class Auth protected ?UserModel $userProvider = null; - public function __construct(AuthConfig $config) + public function __construct(protected AuthConfig $config) { - $this->config = $config; } protected function ensureAuthentication(): void diff --git a/src/Authentication/Actions/Email2FA.php b/src/Authentication/Actions/Email2FA.php index 28216d8cd..f7bf42717 100644 --- a/src/Authentication/Actions/Email2FA.php +++ b/src/Authentication/Actions/Email2FA.php @@ -95,7 +95,7 @@ public function handle(IncomingRequest $request) $email->setMessage($this->view( setting('Auth.views')['action_email_2fa_email'], ['code' => $identity->secret, 'user' => $user, 'ipAddress' => $ipAddress, 'userAgent' => $userAgent, 'date' => $date], - ['debug' => false] + ['debug' => false], )); if ($email->send(false) === false) { @@ -160,7 +160,7 @@ public function createIdentity(User $user): string 'name' => 'login', 'extra' => lang('Auth.need2FA'), ], - $generator + $generator, ); } @@ -174,7 +174,7 @@ private function getIdentity(User $user): ?UserIdentity return $identityModel->getIdentityByType( $user, - $this->type + $this->type, ); } diff --git a/src/Authentication/Actions/EmailActivator.php b/src/Authentication/Actions/EmailActivator.php index 2b47f374e..2ca9aa611 100644 --- a/src/Authentication/Actions/EmailActivator.php +++ b/src/Authentication/Actions/EmailActivator.php @@ -16,7 +16,6 @@ use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RedirectResponse; -use CodeIgniter\HTTP\Response; use CodeIgniter\I18n\Time; use CodeIgniter\Shield\Authentication\Authenticators\Session; use CodeIgniter\Shield\Entities\User; @@ -50,7 +49,7 @@ public function show(): string $userEmail = $user->email; if ($userEmail === null) { throw new LogicException( - 'Email Activation needs user email address. user_id: ' . $user->id + 'Email Activation needs user email address. user_id: ' . $user->id, ); } @@ -72,7 +71,7 @@ public function show(): string $email->setMessage($this->view( setting('Auth.views')['action_email_activate_email'], ['code' => $code, 'user' => $user, 'ipAddress' => $ipAddress, 'userAgent' => $userAgent, 'date' => $date], - ['debug' => false] + ['debug' => false], )); if ($email->send(false) === false) { @@ -88,10 +87,8 @@ public function show(): string /** * This method is unused. - * - * @return Response|string */ - public function handle(IncomingRequest $request) + public function handle(IncomingRequest $request): never { throw new PageNotFoundException(); } @@ -155,7 +152,7 @@ public function createIdentity(User $user): string 'name' => 'register', 'extra' => lang('Auth.needVerification'), ], - $generator + $generator, ); } @@ -169,7 +166,7 @@ private function getIdentity(User $user): ?UserIdentity return $identityModel->getIdentityByType( $user, - $this->type + $this->type, ); } diff --git a/src/Authentication/Authentication.php b/src/Authentication/Authentication.php index 9e2dd2d75..2d4b3a273 100644 --- a/src/Authentication/Authentication.php +++ b/src/Authentication/Authentication.php @@ -30,11 +30,9 @@ class Authentication protected array $instances = []; protected ?UserModel $userProvider = null; - protected AuthConfig $config; - public function __construct(AuthConfig $config) + public function __construct(protected AuthConfig $config) { - $this->config = $config; } /** diff --git a/src/Authentication/Authenticators/AccessTokens.php b/src/Authentication/Authenticators/AccessTokens.php index 6356ab1a8..ce86155a9 100644 --- a/src/Authentication/Authenticators/AccessTokens.php +++ b/src/Authentication/Authenticators/AccessTokens.php @@ -29,18 +29,15 @@ class AccessTokens implements AuthenticatorInterface { public const ID_TYPE_ACCESS_TOKEN = 'access_token'; - /** - * The persistence engine - */ - protected UserModel $provider; - protected ?User $user = null; protected TokenLoginModel $loginModel; - public function __construct(UserModel $provider) - { - $this->provider = $provider; - + /** + * @param UserModel $provider The persistence engine + */ + public function __construct( + protected UserModel $provider, + ) { $this->loginModel = model(TokenLoginModel::class); } @@ -70,7 +67,7 @@ public function attempt(array $credentials): Result $credentials['token'] ?? '', false, $ipAddress, - $userAgent + $userAgent, ); } @@ -89,7 +86,7 @@ public function attempt(array $credentials): Result false, $ipAddress, $userAgent, - $user->id + $user->id, ); } @@ -113,7 +110,7 @@ public function attempt(array $credentials): Result true, $ipAddress, $userAgent, - $this->user->id + $this->user->id, ); } @@ -134,13 +131,13 @@ public function check(array $credentials): Result 'success' => false, 'reason' => lang( 'Auth.noToken', - [config('AuthToken')->authenticatorHeader['tokens']] + [config('AuthToken')->authenticatorHeader['tokens']], ), ]); } - if (strpos($credentials['token'], 'Bearer') === 0) { - $credentials['token'] = trim(substr($credentials['token'], 6)); + if (str_starts_with((string) $credentials['token'], 'Bearer')) { + $credentials['token'] = trim(substr((string) $credentials['token'], 6)); } /** @var UserIdentityModel $identityModel */ @@ -161,7 +158,7 @@ public function check(array $credentials): Result if ( $token->last_used_at && $token->last_used_at->isBefore( - Time::now()->subSeconds(config('AuthToken')->unusedTokenLifetime) + Time::now()->subSeconds(config('AuthToken')->unusedTokenLifetime), ) ) { return new Result([ @@ -202,7 +199,7 @@ public function loggedIn(): bool return $this->attempt([ 'token' => $request->getHeaderLine( - config('AuthToken')->authenticatorHeader['tokens'] + config('AuthToken')->authenticatorHeader['tokens'], ), ])->isOK(); } @@ -231,7 +228,7 @@ public function loginById($userId): void } $user->setAccessToken( - $user->getAccessToken($this->getBearerToken()) + $user->getAccessToken($this->getBearerToken()), ); $this->login($user); @@ -277,7 +274,7 @@ public function recordActiveDate(): void { if (! $this->user instanceof User) { throw new InvalidArgumentException( - __METHOD__ . '() requires logged in user before calling.' + __METHOD__ . '() requires logged in user before calling.', ); } diff --git a/src/Authentication/Authenticators/HmacSha256.php b/src/Authentication/Authenticators/HmacSha256.php index 993ee69c2..482562f01 100644 --- a/src/Authentication/Authenticators/HmacSha256.php +++ b/src/Authentication/Authenticators/HmacSha256.php @@ -30,18 +30,15 @@ class HmacSha256 implements AuthenticatorInterface { public const ID_TYPE_HMAC_TOKEN = 'hmac_sha256'; - /** - * The persistence engine - */ - protected UserModel $provider; - protected ?User $user = null; protected TokenLoginModel $loginModel; - public function __construct(UserModel $provider) - { - $this->provider = $provider; - + /** + * @param UserModel $provider The persistence engine + */ + public function __construct( + protected UserModel $provider, + ) { $this->loginModel = model(TokenLoginModel::class); } @@ -71,7 +68,7 @@ public function attempt(array $credentials): Result $credentials['token'] ?? '', false, $ipAddress, - $userAgent + $userAgent, ); } @@ -90,7 +87,7 @@ public function attempt(array $credentials): Result false, $ipAddress, $userAgent, - $user->id + $user->id, ); } @@ -114,7 +111,7 @@ public function attempt(array $credentials): Result true, $ipAddress, $userAgent, - $this->user->id + $this->user->id, ); } @@ -135,13 +132,13 @@ public function check(array $credentials): Result 'success' => false, 'reason' => lang( 'Auth.noToken', - [config('AuthToken')->authenticatorHeader['hmac']] + [config('AuthToken')->authenticatorHeader['hmac']], ), ]); } - if (strpos($credentials['token'], 'HMAC-SHA256') === 0) { - $credentials['token'] = trim(substr($credentials['token'], 11)); // HMAC-SHA256 + if (str_starts_with((string) $credentials['token'], 'HMAC-SHA256')) { + $credentials['token'] = trim(substr((string) $credentials['token'], 11)); // HMAC-SHA256 } // Extract UserToken and HMACSHA256 Signature from Authorization token @@ -163,7 +160,7 @@ public function check(array $credentials): Result $secretKey = $encrypter->decrypt($token->secret2); // Check signature... - $hash = hash_hmac('sha256', $credentials['body'], $secretKey); + $hash = hash_hmac('sha256', (string) $credentials['body'], $secretKey); if ($hash !== $signature) { return new Result([ 'success' => false, @@ -177,7 +174,7 @@ public function check(array $credentials): Result if ( isset($token->last_used_at) && $token->last_used_at->isBefore( - Time::now()->subSeconds(config('AuthToken')->unusedTokenLifetime) + Time::now()->subSeconds(config('AuthToken')->unusedTokenLifetime), ) ) { return new Result([ @@ -218,7 +215,7 @@ public function loggedIn(): bool return $this->attempt([ 'token' => $request->getHeaderLine( - config('AuthToken')->authenticatorHeader['hmac'] + config('AuthToken')->authenticatorHeader['hmac'], ), ])->isOK(); } @@ -247,7 +244,7 @@ public function loginById($userId): void } $user->setHmacToken( - $user->getHmacToken($this->getHmacKeyFromToken()) + $user->getHmacToken($this->getHmacKeyFromToken()), ); $this->login($user); @@ -339,7 +336,7 @@ public function recordActiveDate(): void { if (! $this->user instanceof User) { throw new InvalidArgumentException( - __METHOD__ . '() requires logged in user before calling.' + __METHOD__ . '() requires logged in user before calling.', ); } diff --git a/src/Authentication/Authenticators/JWT.php b/src/Authentication/Authenticators/JWT.php index 7dc1dd1f6..61deddb20 100644 --- a/src/Authentication/Authenticators/JWT.php +++ b/src/Authentication/Authenticators/JWT.php @@ -40,11 +40,6 @@ class JWT implements AuthenticatorInterface */ public const ID_TYPE_JWT = 'jwt'; - /** - * The persistence engine - */ - protected UserModel $provider; - protected ?User $user = null; protected JWTManager $jwtManager; protected TokenLoginModel $tokenLoginModel; @@ -55,10 +50,12 @@ class JWT implements AuthenticatorInterface */ protected $keyset = 'default'; - public function __construct(UserModel $provider) - { - $this->provider = $provider; - + /** + * @param UserModel $provider The persistence engine + */ + public function __construct( + protected UserModel $provider, + ) { $this->jwtManager = service('jwtmanager'); $this->tokenLoginModel = model(TokenLoginModel::class); } @@ -90,7 +87,7 @@ public function attempt(array $credentials): Result $credentials['token'] ?? '', false, $ipAddress, - $userAgent + $userAgent, ); } @@ -108,7 +105,7 @@ public function attempt(array $credentials): Result false, $ipAddress, $userAgent, - $user->id + $user->id, ); } @@ -130,7 +127,7 @@ public function attempt(array $credentials): Result true, $ipAddress, $userAgent, - $this->user->id + $this->user->id, ); } @@ -153,7 +150,7 @@ public function check(array $credentials): Result 'success' => false, 'reason' => lang( 'Auth.noToken', - [config('AuthJWT')->authenticatorHeader] + [config('AuthJWT')->authenticatorHeader], ), ]); } @@ -225,10 +222,10 @@ public function getTokenFromRequest(RequestInterface $request): string $config = config('AuthJWT'); $tokenHeader = $request->getHeaderLine( - $config->authenticatorHeader ?? 'Authorization' + $config->authenticatorHeader ?? 'Authorization', ); - if (strpos($tokenHeader, 'Bearer') === 0) { + if (str_starts_with($tokenHeader, 'Bearer')) { return trim(substr($tokenHeader, 6)); } @@ -284,7 +281,7 @@ public function recordActiveDate(): void { if (! $this->user instanceof User) { throw new InvalidArgumentException( - __METHOD__ . '() requires logged in user before calling.' + __METHOD__ . '() requires logged in user before calling.', ); } diff --git a/src/Authentication/Authenticators/Session.php b/src/Authentication/Authenticators/Session.php index 4c1b52b1a..31836a631 100644 --- a/src/Authentication/Authenticators/Session.php +++ b/src/Authentication/Authenticators/Session.php @@ -56,11 +56,6 @@ class Session implements AuthenticatorInterface private const STATE_PENDING = 2; // 2FA or Activation required. private const STATE_LOGGED_IN = 3; - /** - * The persistence engine - */ - protected UserModel $provider; - /** * Authenticated or authenticating (pending login) User */ @@ -80,10 +75,12 @@ class Session implements AuthenticatorInterface protected RememberModel $rememberModel; protected UserIdentityModel $userIdentityModel; - public function __construct(UserModel $provider) - { - $this->provider = $provider; - + /** + * @param UserModel $provider The persistence engine + */ + public function __construct( + protected UserModel $provider, + ) { $this->loginModel = model(LoginModel::class); $this->rememberModel = model(RememberModel::class); $this->userIdentityModel = model(UserIdentityModel::class); @@ -103,7 +100,7 @@ private function checkSecurityConfig(): void throw new SecurityException( 'Config\Security::$csrfProtection is set to \'cookie\'.' . ' Same-site attackers may bypass the CSRF protection.' - . ' Please set it to \'session\'.' + . ' Please set it to \'session\'.', ); } } @@ -278,7 +275,7 @@ private function recordLoginAttempt( bool $success, string $ipAddress, string $userAgent, - $userId = null + $userId = null, ): void { // Determine the type of ID we're using. // Standard fields would be email, username, @@ -305,7 +302,7 @@ private function recordLoginAttempt( $success, $ipAddress, $userAgent, - $userId + $userId, ); } @@ -507,7 +504,7 @@ private function getIdentitiesForAction(User $user): array { return $this->userIdentityModel->getIdentitiesByTypes( $user, - $this->getActionTypes() + $this->getActionTypes(), ); } @@ -653,7 +650,7 @@ public function startLogin(User $user): void . ' If a logged in user logs in again with other account, the session data of the previous' . ' user will be used as the new user.' . ' Fix your code to prevent users from logging in without logging out or delete the session data.' - . ' user_id: ' . $userId + . ' user_id: ' . $userId, ); } @@ -740,7 +737,7 @@ public function login(User $user): void 'The user has identities for action, so cannot complete login.' . ' If you want to start to login with auth action, use startLogin() instead.' . ' Or delete identities for action in database.' - . ' user_id: ' . $user->id + . ' user_id: ' . $user->id, ); } // Check auth_action in Session @@ -749,7 +746,7 @@ public function login(User $user): void 'The user has auth action in session, so cannot complete login.' . ' If you want to start to login with auth action, use startLogin() instead.' . ' Or delete `auth_action` and `auth_action_message` in session data.' - . ' user_id: ' . $user->id + . ' user_id: ' . $user->id, ); } @@ -791,7 +788,7 @@ private function removeRememberCookie(): void setting('Auth.sessionConfig')['rememberCookieName'], setting('Cookie.domain'), setting('Cookie.path'), - setting('Cookie.prefix') + setting('Cookie.prefix'), ); } @@ -894,7 +891,7 @@ public function recordActiveDate(): void { if (! $this->user instanceof User) { throw new InvalidArgumentException( - __METHOD__ . '() requires logged in user before calling.' + __METHOD__ . '() requires logged in user before calling.', ); } @@ -922,7 +919,7 @@ protected function rememberUser(User $user): void $user, $selector, $this->hashValidator($validator), - $expires->format('Y-m-d H:i:s') + $expires->format('Y-m-d H:i:s'), ); $this->setRememberMeCookie($rawToken); @@ -953,7 +950,7 @@ private function setRememberMeCookie(string $rawToken): void setting('Cookie.path'), setting('Cookie.prefix'), setting('Cookie.secure'), // Only send over HTTPS? - true // Hide from Javascript? + true, // Hide from Javascript? ); } diff --git a/src/Authentication/HMAC/HmacEncrypter.php b/src/Authentication/HMAC/HmacEncrypter.php index db0db64c6..c8fb309de 100644 --- a/src/Authentication/HMAC/HmacEncrypter.php +++ b/src/Authentication/HMAC/HmacEncrypter.php @@ -39,7 +39,7 @@ class HmacEncrypter /** * Auth Token config */ - private AuthToken $authConfig; + private readonly AuthToken $authConfig; /** * Constructor diff --git a/src/Authentication/JWT/Adapters/FirebaseAdapter.php b/src/Authentication/JWT/Adapters/FirebaseAdapter.php index 0c7bb95ef..ce2032ab1 100644 --- a/src/Authentication/JWT/Adapters/FirebaseAdapter.php +++ b/src/Authentication/JWT/Adapters/FirebaseAdapter.php @@ -45,7 +45,7 @@ public function decode(string $encodedToken, $keyset): stdClass throw new ShieldInvalidArgumentException( 'Invalid Keyset: "' . $keyset . '". ' . $e->getMessage(), 0, - $e + $e, ); } catch (DomainException $e) { // provided algorithm is unsupported OR @@ -72,7 +72,7 @@ public function decode(string $encodedToken, $keyset): stdClass 'error', '[Shield] ' . class_basename($this) . '::' . __FUNCTION__ . '(' . __LINE__ . ') ' - . get_class($e) . ': ' . $e->getMessage() + . $e::class . ': ' . $e->getMessage(), ); throw InvalidTokenException::forInvalidToken($e); @@ -148,7 +148,7 @@ private function createKeysForEncode($keyset): array if ($passphrase !== '') { $key = openssl_pkey_get_private( $config->keys[$keyset][0]['private'], - $passphrase + $passphrase, ); } else { $key = $config->keys[$keyset][0]['private']; diff --git a/src/Authentication/JWT/JWSDecoder.php b/src/Authentication/JWT/JWSDecoder.php index 145eb5623..a5dcc7462 100644 --- a/src/Authentication/JWT/JWSDecoder.php +++ b/src/Authentication/JWT/JWSDecoder.php @@ -18,14 +18,12 @@ class JWSDecoder { - private JWSAdapterInterface $jwsAdapter; - /** * @var string The key group. The array key of Config\AuthJWT::$keys. */ protected $keyset = 'default'; - public function __construct(?JWSAdapterInterface $jwsAdapter = null) + public function __construct(private ?JWSAdapterInterface $jwsAdapter = null) { $this->jwsAdapter = $jwsAdapter ?? new FirebaseAdapter(); } diff --git a/src/Authentication/JWT/JWSEncoder.php b/src/Authentication/JWT/JWSEncoder.php index 458aeec01..699bbf706 100644 --- a/src/Authentication/JWT/JWSEncoder.php +++ b/src/Authentication/JWT/JWSEncoder.php @@ -19,10 +19,7 @@ class JWSEncoder { - protected Time $clock; - protected JWSAdapterInterface $jwsAdapter; - - public function __construct(?JWSAdapterInterface $jwsAdapter = null, ?Time $clock = null) + public function __construct(protected ?JWSAdapterInterface $jwsAdapter = null, protected ?Time $clock = null) { $this->jwsAdapter = $jwsAdapter ?? new FirebaseAdapter(); $this->clock = $clock ?? new Time(); @@ -41,11 +38,11 @@ public function encode( array $claims, ?int $ttl = null, $keyset = 'default', - ?array $headers = null + ?array $headers = null, ): string { assert( (array_key_exists('exp', $claims) && ($ttl !== null)) === false, - 'Cannot pass $claims[\'exp\'] and $ttl at the same time.' + 'Cannot pass $claims[\'exp\'] and $ttl at the same time.', ); /** @var AuthJWT $config */ @@ -53,7 +50,7 @@ public function encode( $payload = array_merge( $config->defaultClaims, - $claims + $claims, ); if (! array_key_exists('iat', $claims)) { @@ -71,7 +68,7 @@ public function encode( return $this->jwsAdapter->encode( $payload, $keyset, - $headers + $headers, ); } } diff --git a/src/Authentication/JWTManager.php b/src/Authentication/JWTManager.php index ad638bc3a..46ca125c9 100644 --- a/src/Authentication/JWTManager.php +++ b/src/Authentication/JWTManager.php @@ -24,14 +24,10 @@ */ class JWTManager { - protected Time $clock; - protected JWSEncoder $jwsEncoder; - protected JWSDecoder $jwsDecoder; - public function __construct( - ?Time $clock = null, - ?JWSEncoder $jwsEncoder = null, - ?JWSDecoder $jwsDecoder = null + protected ?Time $clock = null, + protected ?JWSEncoder $jwsEncoder = null, + protected ?JWSDecoder $jwsDecoder = null, ) { $this->clock = $clock ?? new Time(); $this->jwsEncoder = $jwsEncoder ?? new JWSEncoder(null, $this->clock); @@ -52,7 +48,7 @@ public function generateToken( array $claims = [], ?int $ttl = null, $keyset = 'default', - ?array $headers = null + ?array $headers = null, ): string { $payload = array_merge( $claims, @@ -77,7 +73,7 @@ public function issue( array $claims, ?int $ttl = null, $keyset = 'default', - ?array $headers = null + ?array $headers = null, ): string { return $this->jwsEncoder->encode($claims, $ttl, $keyset, $headers); } diff --git a/src/Authentication/Passwords.php b/src/Authentication/Passwords.php index 5ddca0302..9f0b0653d 100644 --- a/src/Authentication/Passwords.php +++ b/src/Authentication/Passwords.php @@ -26,11 +26,8 @@ */ class Passwords { - protected Auth $config; - - public function __construct(Auth $config) + public function __construct(protected Auth $config) { - $this->config = $config; } /** @@ -72,10 +69,10 @@ public function hashDanger(string $password) { return password_hash( base64_encode( - hash('sha384', $password, true) + hash('sha384', $password, true), ), $this->config->hashAlgorithm, - $this->getHashOptions() + $this->getHashOptions(), ); } diff --git a/src/Authentication/Passwords/BaseValidator.php b/src/Authentication/Passwords/BaseValidator.php index 64e7a3eac..b08a5e879 100644 --- a/src/Authentication/Passwords/BaseValidator.php +++ b/src/Authentication/Passwords/BaseValidator.php @@ -17,13 +17,11 @@ class BaseValidator { - protected AuthConfig $config; protected ?string $error = null; protected ?string $suggestion = null; - public function __construct(AuthConfig $config) + public function __construct(protected AuthConfig $config) { - $this->config = $config; } /** diff --git a/src/Authentication/Passwords/NothingPersonalValidator.php b/src/Authentication/Passwords/NothingPersonalValidator.php index 8d7f6d07d..6ea9bc139 100644 --- a/src/Authentication/Passwords/NothingPersonalValidator.php +++ b/src/Authentication/Passwords/NothingPersonalValidator.php @@ -131,8 +131,8 @@ protected function isNotPersonal(string $password, ?User $user): bool } // look both ways in case password is subset of needle - if (strpos($haystack, $needle) !== false - || strpos($needle, $haystack) !== false) { + if (str_contains($haystack, $needle) + || str_contains($needle, $haystack)) { $valid = false; break 2; } @@ -198,7 +198,7 @@ protected function isNotSimilar(string $password, ?User $user): bool protected function strip_explode(string $str): array { $stripped = preg_replace('/[\W_]+/', ' ', $str); - $parts = explode(' ', trim($stripped)); + $parts = explode(' ', trim((string) $stripped)); // If it's not already there put the untouched input at the top of the array if (! in_array($str, $parts, true)) { diff --git a/src/Authentication/Passwords/PwnedValidator.php b/src/Authentication/Passwords/PwnedValidator.php index ff933fe49..5094087e1 100644 --- a/src/Authentication/Passwords/PwnedValidator.php +++ b/src/Authentication/Passwords/PwnedValidator.php @@ -54,7 +54,7 @@ public function check(string $password, ?User $user = null): Result $response = $client->get( 'range/' . $rangeHash, - ['headers' => ['Accept' => 'text/plain']] + ['headers' => ['Accept' => 'text/plain']], ); } catch (HTTPException $e) { $exception = AuthenticationException::forHIBPCurlFail($e); @@ -64,7 +64,7 @@ public function check(string $password, ?User $user = null): Result } $range = $response->getBody(); - $startPos = strpos($range, $searchHash); + $startPos = strpos((string) $range, $searchHash); if ($startPos === false) { return new Result([ 'success' => true, @@ -72,8 +72,8 @@ public function check(string $password, ?User $user = null): Result } $startPos += 36; // right after the delimiter (:) - $endPos = strpos($range, "\r\n", $startPos); - $hits = $endPos !== false ? (int) substr($range, $startPos, $endPos - $startPos) : (int) substr($range, $startPos); + $endPos = strpos((string) $range, "\r\n", $startPos); + $hits = $endPos !== false ? (int) substr((string) $range, $startPos, $endPos - $startPos) : (int) substr((string) $range, $startPos); $wording = $hits > 1 ? 'databases' : 'a database'; diff --git a/src/Authorization/Traits/Authorizable.php b/src/Authorization/Traits/Authorizable.php index c0b1acf2a..6e4f4b21b 100644 --- a/src/Authorization/Traits/Authorizable.php +++ b/src/Authorization/Traits/Authorizable.php @@ -255,10 +255,10 @@ public function can(string ...$permissions): bool foreach ($permissions as $permission) { // Permission must contain a scope and action - if (strpos($permission, '.') === false) { + if (! str_contains($permission, '.')) { throw new LogicException( 'A permission must be a string consisting of a scope and action, like `users.create`.' - . ' Invalid permission: ' . $permission + . ' Invalid permission: ' . $permission, ); } diff --git a/src/Collectors/Auth.php b/src/Collectors/Auth.php index a0e8331b1..7ce74f148 100644 --- a/src/Collectors/Auth.php +++ b/src/Collectors/Auth.php @@ -53,7 +53,7 @@ class Auth extends BaseCollector */ protected $title = 'Auth'; - private ShieldAuth $auth; + private readonly ShieldAuth $auth; public function __construct() { @@ -65,7 +65,7 @@ public function __construct() */ public function getTitleDetails(): string { - return ShieldAuth::SHIELD_VERSION . ' | ' . get_class($this->auth->getAuthenticator()); + return ShieldAuth::SHIELD_VERSION . ' | ' . $this->auth->getAuthenticator()::class; } /** diff --git a/src/Commands/BaseCommand.php b/src/Commands/BaseCommand.php index f7ad9962d..478375aa9 100644 --- a/src/Commands/BaseCommand.php +++ b/src/Commands/BaseCommand.php @@ -57,7 +57,7 @@ protected function prompt(string $field, $options = null, $validation = null): s protected function write( string $text = '', ?string $foreground = null, - ?string $background = null + ?string $background = null, ): void { self::$io->write($text, $foreground, $background); } @@ -68,7 +68,7 @@ protected function write( protected function error( string $text, string $foreground = 'light_red', - ?string $background = null + ?string $background = null, ): void { self::$io->error($text, $foreground, $background); } diff --git a/src/Commands/Hmac.php b/src/Commands/Hmac.php index 08fdcb7d8..d3961b07f 100644 --- a/src/Commands/Hmac.php +++ b/src/Commands/Hmac.php @@ -86,22 +86,12 @@ public function run(array $params): int $this->encrypter = new HmacEncrypter(); try { - switch ($action) { - case 'encrypt': - $this->encrypt(); - break; - - case 'decrypt': - $this->decrypt(); - break; - - case 'reencrypt': - $this->reEncrypt(); - break; - - default: - throw new BadInputException('Unrecognized Command'); - } + match ($action) { + 'encrypt' => $this->encrypt(), + 'decrypt' => $this->decrypt(), + 'reencrypt' => $this->reEncrypt(), + default => throw new BadInputException('Unrecognized Command'), + }; } catch (Exception $e) { $this->write($e->getMessage(), 'red'); @@ -141,7 +131,7 @@ static function ($identity) use ($uIdModelSub, $encrypter, $that): void { } catch (RuntimeException $e) { $that->error('id: ' . $identity->id . ', ' . $e->getMessage()); } - } + }, ); } @@ -171,7 +161,7 @@ static function ($identity) use ($uIdModelSub, $encrypter, $that): void { $uIdModelSub->save($identity); $that->write('id: ' . $identity->id . ', decrypted.'); - } + }, ); } @@ -203,7 +193,7 @@ static function ($identity) use ($uIdModelSub, $encrypter, $that): void { $uIdModelSub->save($identity); $that->write('id: ' . $identity->id . ', Re-encrypted.'); - } + }, ); } } diff --git a/src/Commands/User.php b/src/Commands/User.php index 8e97f777e..ad9748df4 100644 --- a/src/Commands/User.php +++ b/src/Commands/User.php @@ -145,7 +145,7 @@ public function run(array $params): int if ($action === null || ! in_array($action, $this->validActions, true)) { $this->write( 'Specify a valid action: ' . implode(',', $this->validActions), - 'red' + 'red', ); return EXIT_ERROR; @@ -277,12 +277,12 @@ private function create(?string $username = null, ?string $email = null, ?string $password = $this->prompt( 'Password', null, - $this->validationRules['password']['rules'] + $this->validationRules['password']['rules'], ); $passwordConfirm = $this->prompt( 'Password confirmation', null, - $this->validationRules['password']['rules'] + $this->validationRules['password']['rules'], ); if ($password !== $passwordConfirm) { @@ -399,7 +399,7 @@ private function deactivate(?string $username = null, ?string $email = null): vo private function changename( ?string $username = null, ?string $email = null, - ?string $newUsername = null + ?string $newUsername = null, ): void { $user = $this->findUser('Change username', $username, $email); @@ -440,7 +440,7 @@ private function changename( private function changeemail( ?string $username = null, ?string $email = null, - ?string $newEmail = null + ?string $newEmail = null, ): void { $user = $this->findUser('Change email', $username, $email); @@ -491,7 +491,7 @@ private function delete(int $userid = 0, ?string $username = null, ?string $emai $confirm = $this->prompt( 'Delete the user "' . $user->username . '" (' . $user->email . ') ?', - ['y', 'n'] + ['y', 'n'], ); if ($confirm === 'y') { @@ -529,12 +529,12 @@ private function password($username = null, $email = null): void $password = $this->prompt( 'Password', null, - $this->validationRules['password']['rules'] + $this->validationRules['password']['rules'], ); $passwordConfirm = $this->prompt( 'Password confirmation', null, - $this->validationRules['password']['rules'] + $this->validationRules['password']['rules'], ); if ($password !== $passwordConfirm) { @@ -566,7 +566,7 @@ private function list(?string $username = null, ?string $email = null): void ->join( $this->tables['identities'], $this->tables['users'] . '.id = ' . $this->tables['identities'] . '.user_id', - 'LEFT' + 'LEFT', ) ->groupStart() ->where($this->tables['identities'] . '.type', Session::ID_TYPE_EMAIL_PASSWORD) @@ -612,7 +612,7 @@ private function addgroup($group = null, $username = null, $email = null): void $confirm = $this->prompt( 'Add the user "' . $user->username . '" to the group "' . $group . '" ?', - ['y', 'n'] + ['y', 'n'], ); if ($confirm === 'y') { @@ -622,7 +622,7 @@ private function addgroup($group = null, $username = null, $email = null): void } else { $this->write( 'Addition of the user "' . $user->username . '" to the group "' . $group . '" cancelled', - 'yellow' + 'yellow', ); } } @@ -649,7 +649,7 @@ private function removegroup($group = null, $username = null, $email = null): vo $confirm = $this->prompt( 'Remove the user "' . $user->username . '" from the group "' . $group . '" ?', - ['y', 'n'] + ['y', 'n'], ); if ($confirm === 'y') { @@ -679,7 +679,7 @@ private function findUser($question = '', $username = null, $email = null): User $email = $this->prompt( 'Email', null, - 'required' + 'required', ); } } @@ -690,7 +690,7 @@ private function findUser($question = '', $username = null, $email = null): User ->join( $this->tables['identities'], $this->tables['users'] . '.id = ' . $this->tables['identities'] . '.user_id', - 'LEFT' + 'LEFT', ) ->groupStart() ->where($this->tables['identities'] . '.type', Session::ID_TYPE_EMAIL_PASSWORD) diff --git a/src/Commands/Utils/InputOutput.php b/src/Commands/Utils/InputOutput.php index c6a3ceabc..72f79a572 100644 --- a/src/Commands/Utils/InputOutput.php +++ b/src/Commands/Utils/InputOutput.php @@ -37,7 +37,7 @@ public function prompt(string $field, $options = null, $validation = null): stri public function write( string $text = '', ?string $foreground = null, - ?string $background = null + ?string $background = null, ): void { CLI::write($text, $foreground, $background); } diff --git a/src/Config/Auth.php b/src/Config/Auth.php index 9df36cd77..c0f84a4b9 100644 --- a/src/Config/Auth.php +++ b/src/Config/Auth.php @@ -506,23 +506,10 @@ public function groupDeniedRedirect(): string */ protected function getUrl(string $url): string { - // To accommodate all url patterns - $final_url = ''; - - switch (true) { - case strpos($url, 'http://') === 0 || strpos($url, 'https://') === 0: // URL begins with 'http' or 'https'. E.g. http://example.com - $final_url = $url; - break; - - case route_to($url) !== false: // URL is a named-route - $final_url = rtrim(url_to($url), '/ '); - break; - - default: // URL is a route (URI path) - $final_url = rtrim(site_url($url), '/ '); - break; - } - - return $final_url; + return match (true) { + str_starts_with($url, 'http://') || str_starts_with($url, 'https://') => $url, + route_to($url) !== false => rtrim(url_to($url), '/ '), + default => rtrim(site_url($url), '/ '), + }; } } diff --git a/src/Controllers/ActionController.php b/src/Controllers/ActionController.php index 73e356786..8ca9ebd06 100644 --- a/src/Controllers/ActionController.php +++ b/src/Controllers/ActionController.php @@ -43,7 +43,7 @@ public function _remap(string $method, ...$params) // Grab our action instance if one has been set. $this->action = $authenticator->getAction(); - if (empty($this->action) || ! $this->action instanceof ActionInterface) { + if (! $this->action instanceof ActionInterface) { throw new PageNotFoundException(); } diff --git a/src/Controllers/MagicLinkController.php b/src/Controllers/MagicLinkController.php index df77e1a4b..bb203f9c6 100644 --- a/src/Controllers/MagicLinkController.php +++ b/src/Controllers/MagicLinkController.php @@ -128,7 +128,7 @@ public function loginAction() $email->setMessage($this->view( setting('Auth.views')['magic-link-email'], ['token' => $token, 'user' => $user, 'ipAddress' => $ipAddress, 'userAgent' => $userAgent, 'date' => $date], - ['debug' => false] + ['debug' => false], )); if ($email->send(false) === false) { @@ -223,7 +223,7 @@ public function verify(): RedirectResponse private function recordLoginAttempt( string $identifier, bool $success, - $userId = null + $userId = null, ): void { /** @var LoginModel $loginModel */ $loginModel = model(LoginModel::class); @@ -234,7 +234,7 @@ private function recordLoginAttempt( $success, $this->request->getIPAddress(), (string) $this->request->getUserAgent(), - $userId + $userId, ); } diff --git a/src/Controllers/RegisterController.php b/src/Controllers/RegisterController.php index b85e90082..72d4e8109 100644 --- a/src/Controllers/RegisterController.php +++ b/src/Controllers/RegisterController.php @@ -39,12 +39,12 @@ class RegisterController extends BaseController public function initController( RequestInterface $request, ResponseInterface $response, - LoggerInterface $logger + LoggerInterface $logger, ): void { parent::initController( $request, $response, - $logger + $logger, ); } @@ -112,7 +112,7 @@ public function registerAction(): RedirectResponse try { $users->save($user); - } catch (ValidationException $e) { + } catch (ValidationException) { return redirect()->back()->withInput()->with('errors', $users->errors()); } diff --git a/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php b/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php index 2833e81cd..6b75e4e31 100644 --- a/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php +++ b/src/Database/Migrations/2020-12-28-223112_create_auth_tables.php @@ -24,7 +24,7 @@ class CreateAuthTables extends Migration */ private array $tables; - private array $attributes; + private readonly array $attributes; public function __construct(?Forge $forge = null) { diff --git a/src/Filters/AuthRates.php b/src/Filters/AuthRates.php index a533cf6e5..852225570 100644 --- a/src/Filters/AuthRates.php +++ b/src/Filters/AuthRates.php @@ -50,7 +50,7 @@ public function before(RequestInterface $request, $arguments = null) if ($throttler->check(md5($request->getIPAddress()), 10, MINUTE, 1) === false) { return service('response')->setStatusCode( 429, - lang('Auth.throttled', [$throttler->getTokenTime()]) // message + lang('Auth.throttled', [$throttler->getTokenTime()]), // message ); } } diff --git a/src/Models/GroupModel.php b/src/Models/GroupModel.php index d08c8774d..9d4e5b8ce 100644 --- a/src/Models/GroupModel.php +++ b/src/Models/GroupModel.php @@ -62,9 +62,8 @@ public function deleteAll($userId): void /** * @param int|string $userId - * @param mixed $cache */ - public function deleteNotIn($userId, $cache): void + public function deleteNotIn($userId, mixed $cache): void { $return = $this->builder() ->where('user_id', $userId) diff --git a/src/Models/LoginModel.php b/src/Models/LoginModel.php index 76f5cbd6d..eb22d8d8b 100644 --- a/src/Models/LoginModel.php +++ b/src/Models/LoginModel.php @@ -66,7 +66,7 @@ public function recordLoginAttempt( bool $success, ?string $ipAddress = null, ?string $userAgent = null, - $userId = null + $userId = null, ): void { $this->disableDBDebug(); diff --git a/src/Models/PermissionModel.php b/src/Models/PermissionModel.php index 84dd28199..fc508ef73 100644 --- a/src/Models/PermissionModel.php +++ b/src/Models/PermissionModel.php @@ -62,9 +62,8 @@ public function deleteAll($userId): void /** * @param int|string $userId - * @param mixed $cache */ - public function deleteNotIn($userId, $cache): void + public function deleteNotIn($userId, mixed $cache): void { $return = $this->builder() ->where('user_id', $userId) diff --git a/src/Models/UserIdentityModel.php b/src/Models/UserIdentityModel.php index d65a1810b..69f9af62a 100644 --- a/src/Models/UserIdentityModel.php +++ b/src/Models/UserIdentityModel.php @@ -96,7 +96,7 @@ private function checkUserId(User $user): void { if ($user->id === null) { throw new LogicException( - '"$user->id" is null. You should not use the incomplete User object.' + '"$user->id" is null. You should not use the incomplete User object.', ); } } @@ -112,7 +112,7 @@ private function checkUserId(User $user): void public function createCodeIdentity( User $user, array $data, - callable $codeGenerator + callable $codeGenerator, ): string { $this->checkUserId($user); diff --git a/src/Models/UserModel.php b/src/Models/UserModel.php index 8eae4d66a..e4a002fbb 100644 --- a/src/Models/UserModel.php +++ b/src/Models/UserModel.php @@ -204,20 +204,20 @@ public function findByCredentials(array $credentials): ?User foreach ($credentials as $key => $value) { $this->where( 'LOWER(' . $this->db->protectIdentifiers($this->table . ".{$key}") . ')', - strtolower($value) + strtolower($value), ); } if ($email !== null) { /** @var array|null $data */ $data = $this->select( - sprintf('%1$s.*, %2$s.secret as email, %2$s.secret2 as password_hash', $this->table, $this->tables['identities']) + sprintf('%1$s.*, %2$s.secret as email, %2$s.secret2 as password_hash', $this->table, $this->tables['identities']), ) ->join($this->tables['identities'], sprintf('%1$s.user_id = %2$s.id', $this->tables['identities'], $this->table)) ->where($this->tables['identities'] . '.type', Session::ID_TYPE_EMAIL_PASSWORD) ->where( 'LOWER(' . $this->db->protectIdentifiers($this->tables['identities'] . '.secret') . ')', - strtolower($email) + strtolower($email), ) ->asArray() ->first(); diff --git a/src/Test/MockInputOutput.php b/src/Test/MockInputOutput.php index c3c2f635d..143da56b3 100644 --- a/src/Test/MockInputOutput.php +++ b/src/Test/MockInputOutput.php @@ -84,7 +84,7 @@ public function prompt(string $field, $options = null, $validation = null): stri public function write( string $text = '', ?string $foreground = null, - ?string $background = null + ?string $background = null, ): void { CITestStreamFilter::registration(); CITestStreamFilter::addOutputFilter(); diff --git a/src/Traits/Activatable.php b/src/Traits/Activatable.php index b75808076..8721863d0 100644 --- a/src/Traits/Activatable.php +++ b/src/Traits/Activatable.php @@ -60,6 +60,6 @@ public function deactivate(): void */ private function shouldActivate(): bool { - return strpos(setting('Auth.actions')['register'] ?? '', 'Activator') !== false; + return str_contains(setting('Auth.actions')['register'] ?? '', 'Activator'); } } diff --git a/src/Validation/ValidationRules.php b/src/Validation/ValidationRules.php index 4e1284fb7..46dd347c6 100644 --- a/src/Validation/ValidationRules.php +++ b/src/Validation/ValidationRules.php @@ -44,13 +44,13 @@ public function getRegistrationRules(): array $usernameRules = $this->config->usernameValidationRules; $usernameRules['rules'][] = sprintf( 'is_unique[%s.username]', - $this->tables['users'] + $this->tables['users'], ); $emailRules = $this->config->emailValidationRules; $emailRules['rules'][] = sprintf( 'is_unique[%s.secret]', - $this->tables['identities'] + $this->tables['identities'], ); $passwordRules = $this->getPasswordRules(); diff --git a/tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php b/tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php index 43a6d7173..4fafbd7e3 100644 --- a/tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php +++ b/tests/Authentication/Authenticators/AccessTokenAuthenticatorTest.php @@ -121,7 +121,7 @@ public function testCheckNoToken(): void $this->assertFalse($result->isOK()); $this->assertSame( lang('Auth.noToken', [config('AuthToken')->authenticatorHeader['tokens']]), - $result->reason() + $result->reason(), ); } diff --git a/tests/Authentication/Authenticators/HmacAuthenticatorTest.php b/tests/Authentication/Authenticators/HmacAuthenticatorTest.php index da0ac2b94..790a7291a 100644 --- a/tests/Authentication/Authenticators/HmacAuthenticatorTest.php +++ b/tests/Authentication/Authenticators/HmacAuthenticatorTest.php @@ -95,7 +95,7 @@ public function testLoginByIdBadId(): void try { $this->auth->loginById(0); - } catch (AuthenticationException $e) { + } catch (AuthenticationException) { // Failed login } @@ -142,7 +142,7 @@ public function testCheckNoToken(): void $this->assertFalse($result->isOK()); $this->assertSame( lang('Auth.noToken', [config('AuthToken')->authenticatorHeader['hmac']]), - $result->reason() + $result->reason(), ); } diff --git a/tests/Authentication/Authenticators/JWTAuthenticatorTest.php b/tests/Authentication/Authenticators/JWTAuthenticatorTest.php index 13e64eacd..fc28d0cf1 100644 --- a/tests/Authentication/Authenticators/JWTAuthenticatorTest.php +++ b/tests/Authentication/Authenticators/JWTAuthenticatorTest.php @@ -115,7 +115,7 @@ public function testCheckNoToken(): void $this->assertFalse($result->isOK()); $this->assertSame( \lang('Auth.noToken', [config('AuthJWT')->authenticatorHeader]), - $result->reason() + $result->reason(), ); } @@ -265,7 +265,7 @@ public function testRecordActiveDateNoUser(): void { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage( - 'Authentication\Authenticators\JWT::recordActiveDate() requires logged in user before calling.' + 'Authentication\Authenticators\JWT::recordActiveDate() requires logged in user before calling.', ); $this->auth->recordActiveDate(); diff --git a/tests/Authentication/Authenticators/SessionAuthenticatorTest.php b/tests/Authentication/Authenticators/SessionAuthenticatorTest.php index f33c543d2..617d5145c 100644 --- a/tests/Authentication/Authenticators/SessionAuthenticatorTest.php +++ b/tests/Authentication/Authenticators/SessionAuthenticatorTest.php @@ -364,7 +364,7 @@ public function testAttemptUserHavingSessionDataAttemptsAgain(): void $this->expectException(LogicException::class); $this->expectExceptionMessage( - 'The user has User Info in Session, so already logged in or in pending login state.' + 'The user has User Info in Session, so already logged in or in pending login state.', ); $this->user->createEmailIdentity([ diff --git a/tests/Authentication/Filters/AbstractFilterTestCase.php b/tests/Authentication/Filters/AbstractFilterTestCase.php index 906f4ea85..9897443bc 100644 --- a/tests/Authentication/Filters/AbstractFilterTestCase.php +++ b/tests/Authentication/Filters/AbstractFilterTestCase.php @@ -72,7 +72,7 @@ static function ($routes): void { $routes->get('protected-route', static function (): void { echo 'Protected'; }); - } + }, ); $routes->get('open-route', static function (): void { echo 'Open'; diff --git a/tests/Authentication/HasAccessTokensTest.php b/tests/Authentication/HasAccessTokensTest.php index f86668f1d..e00154f89 100644 --- a/tests/Authentication/HasAccessTokensTest.php +++ b/tests/Authentication/HasAccessTokensTest.php @@ -59,11 +59,11 @@ public function testAccessTokens(): void // Give the user a couple of access tokens $token1 = fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => 'access_token', 'secret' => 'secretToken1'] + ['user_id' => $this->user->id, 'type' => 'access_token', 'secret' => 'secretToken1'], ); $token2 = fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => 'access_token', 'secret' => 'secretToken2'] + ['user_id' => $this->user->id, 'type' => 'access_token', 'secret' => 'secretToken2'], ); /** @var list $tokens */ diff --git a/tests/Authentication/HasHmacTokensTest.php b/tests/Authentication/HasHmacTokensTest.php index 0b5394bab..e9d6a3451 100644 --- a/tests/Authentication/HasHmacTokensTest.php +++ b/tests/Authentication/HasHmacTokensTest.php @@ -57,12 +57,12 @@ public function testHmacTokens(): void // Give the user a couple of access tokens $token1 = fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => 'hmac_sha256', 'secret' => 'key1', 'secret2' => 'd862cd9ddc23e960ca6d45a3e0b64c7509f0c0ef0e5f7b64be8910a6a714c89b83fab95251bbf17f6c84b42c26cf460a28ea969591dc64b1f5c4b323f47615d2e8cbe4c62118001d3274e0f25850b0ac2617bc43119af22c99a1a83072002267177da01f9f37225435e1914be004f4d35a49869b737ed10ab232c1ed1048bb9'] + ['user_id' => $this->user->id, 'type' => 'hmac_sha256', 'secret' => 'key1', 'secret2' => 'd862cd9ddc23e960ca6d45a3e0b64c7509f0c0ef0e5f7b64be8910a6a714c89b83fab95251bbf17f6c84b42c26cf460a28ea969591dc64b1f5c4b323f47615d2e8cbe4c62118001d3274e0f25850b0ac2617bc43119af22c99a1a83072002267177da01f9f37225435e1914be004f4d35a49869b737ed10ab232c1ed1048bb9'], ); $token2 = fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => 'hmac_sha256', 'secret' => 'key2', 'secret2' => 'd862cd9ddc23e960ca6d45a3e0b64c7509f0c0ef0e5f7b64be8910a6a714c89b83fab95251bbf17f6c84b42c26cf460a28ea969591dc64b1f5c4b323f47615d2e8cbe4c62118001d3274e0f25850b0ac2617bc43119af22c99a1a83072002267177da01f9f37225435e1914be004f4d35a49869b737ed10ab232c1ed1048bb9'] + ['user_id' => $this->user->id, 'type' => 'hmac_sha256', 'secret' => 'key2', 'secret2' => 'd862cd9ddc23e960ca6d45a3e0b64c7509f0c0ef0e5f7b64be8910a6a714c89b83fab95251bbf17f6c84b42c26cf460a28ea969591dc64b1f5c4b323f47615d2e8cbe4c62118001d3274e0f25850b0ac2617bc43119af22c99a1a83072002267177da01f9f37225435e1914be004f4d35a49869b737ed10ab232c1ed1048bb9'], ); $tokens = $this->user->hmacTokens(); diff --git a/tests/Commands/SetupTest.php b/tests/Commands/SetupTest.php index f695cce21..016463a08 100644 --- a/tests/Commands/SetupTest.php +++ b/tests/Commands/SetupTest.php @@ -93,11 +93,11 @@ public function testRun(): void Updated: vfs://root/Config/Routes.php Updated: We have updated file \'vfs://root/Config/Security.php\' for security reasons. Updated: vfs://root/Config/Email.php', - $result + $result, ); $this->assertStringContainsString( 'Running all new migrations...', - $result + $result, ); } @@ -127,7 +127,7 @@ public function testRunEmailConfigIsFine(): void Updated: vfs://root/Config/Autoload.php Updated: vfs://root/Config/Routes.php Updated: We have updated file \'vfs://root/Config/Security.php\' for security reasons.', - $result + $result, ); } @@ -162,7 +162,7 @@ class Autoload extends AutoloadConfig $this->assertStringContainsString( "public \$helpers = ['text', 'form', 'auth', 'setting'];", - $output + $output, ); } @@ -174,7 +174,7 @@ private function createFilesystem(): string $root = vfsStream::setup('root'); vfsStream::copyFromFileSystem( APPPATH, - $root + $root, ); return $root->url() . '/'; diff --git a/tests/Commands/UserTest.php b/tests/Commands/UserTest.php index 3823d8314..4ab6a275b 100644 --- a/tests/Commands/UserTest.php +++ b/tests/Commands/UserTest.php @@ -66,7 +66,7 @@ public function testNoAction(): void $this->assertStringContainsString( 'Specify a valid action: create,activate,deactivate,changename,changeemail,delete,password,list,addgroup,removegroup', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); } @@ -81,7 +81,7 @@ public function testCreate(): void $this->assertStringContainsString( 'User "user1" created', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -111,11 +111,11 @@ public function testCreateWithGroupBeta(): void $this->assertStringContainsString( 'User "user1" created', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $this->assertStringContainsString( 'The user is added to group "beta"', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -145,7 +145,7 @@ public function testCreateWithInvalidGroup(): void $this->assertStringContainsString( 'Invalid group: "invalid"', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -170,11 +170,11 @@ public function testCreateNotUniqueName(): void $this->assertStringContainsString( 'The Username field must contain a unique value.', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $this->assertStringContainsString( 'User creation aborted', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -199,7 +199,7 @@ public function testCreatePasswordNotMatch(): void $this->assertStringContainsString( "The passwords don't match", - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -240,7 +240,7 @@ public function testActivate(): void $this->assertStringContainsString( 'User "user2" activated', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $user = $users->findByCredentials(['email' => 'user2@example.com']); @@ -264,7 +264,7 @@ public function testDeactivate(): void $this->assertStringContainsString( 'User "user3" deactivated', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -289,7 +289,7 @@ public function testChangename(): void $this->assertStringContainsString( 'Username "user4" changed to "newuser4"', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -314,11 +314,11 @@ public function testChangenameInvalidName(): void $this->assertStringContainsString( 'The Username field must be at least 3 characters in length.', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $this->assertStringContainsString( 'User name change aborted', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -343,7 +343,7 @@ public function testChangeemail(): void $this->assertStringContainsString( 'Email for "user5" changed to newuser5@example.jp', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -368,11 +368,11 @@ public function testChangeemailInvalidEmail(): void $this->assertStringContainsString( 'The Email Address field must contain a valid email address.', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $this->assertStringContainsString( 'User email change aborted', - $this->io->getFirstOutput() + $this->io->getFirstOutput(), ); $users = model(UserModel::class); @@ -394,7 +394,7 @@ public function testDelete(): void $this->assertStringContainsString( 'User "user6" deleted', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -416,7 +416,7 @@ public function testDeleteById(): void $this->assertStringContainsString( 'User "user6" deleted', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -438,7 +438,7 @@ public function testDeleteUserNotExist(): void $this->assertStringContainsString( "User doesn't exist", - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -463,7 +463,7 @@ public function testPassword(): void $this->assertStringContainsString( 'Password for "user7" set', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $user = $users->findByCredentials(['email' => 'user7@example.com']); @@ -489,7 +489,7 @@ public function testPasswordWithoutOptionsAndSpecifyEmail(): void $this->assertStringContainsString( 'Password for "user7" set', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $user = $users->findByCredentials(['email' => 'user7@example.com']); @@ -515,7 +515,7 @@ public function testPasswordNotMatch(): void $this->assertStringContainsString( "The passwords don't match", - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $user = $users->findByCredentials(['email' => 'user7@example.com']); @@ -544,7 +544,7 @@ public function testList(): void 1 user8 (user8@example.com) 2 user9 (user9@example.com) ', - $this->getOutputWithoutColorCode() + $this->getOutputWithoutColorCode(), ); } @@ -569,7 +569,7 @@ public function testListByEmail(): void 'Id User 2 user9 (user9@example.com) ', - $this->getOutputWithoutColorCode() + $this->getOutputWithoutColorCode(), ); } @@ -587,7 +587,7 @@ public function testAddgroup(): void $this->assertStringContainsString( 'User "user10" added to group "admin"', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -609,7 +609,7 @@ public function testAddgroupWithInvalidGroup(): void $this->assertStringContainsString( 'Invalid group: "invalid"', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); } @@ -627,7 +627,7 @@ public function testAddgroupCancel(): void $this->assertStringContainsString( 'Addition of the user "user10" to the group "admin" cancelled', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -653,7 +653,7 @@ public function testRemovegroup(): void $this->assertStringContainsString( 'User "user11" removed from group "admin"', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -679,7 +679,7 @@ public function testRemovegroupWithInvalidGroup(): void $this->assertStringContainsString( 'Invalid group: "invalid"', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); @@ -705,7 +705,7 @@ public function testRemovegroupCancel(): void $this->assertStringContainsString( 'Removal of the user "user11" from the group "admin" cancelled', - $this->io->getLastOutput() + $this->io->getLastOutput(), ); $users = model(UserModel::class); diff --git a/tests/Controllers/ActionsTest.php b/tests/Controllers/ActionsTest.php index 8f30afb99..b409e0cd7 100644 --- a/tests/Controllers/ActionsTest.php +++ b/tests/Controllers/ActionsTest.php @@ -245,11 +245,11 @@ public function testEmailActivateShow(): void // Should have sent an email with the link.... $this->assertStringContainsString( 'Please use the code below to activate your account and start using the site', - service('email')->archive['body'] + service('email')->archive['body'], ); $this->assertMatchesRegularExpression( '!

[0-9]{6}

!', - service('email')->archive['body'] + service('email')->archive['body'], ); // Should have included the username in the email diff --git a/tests/Controllers/LoginTest.php b/tests/Controllers/LoginTest.php index 95716dc24..acdb1e894 100644 --- a/tests/Controllers/LoginTest.php +++ b/tests/Controllers/LoginTest.php @@ -85,7 +85,7 @@ public function testLoginTooLongPasswordDefault(): void $result->assertSessionMissing('error'); $result->assertSessionHas( 'errors', - ['password' => 'Password cannot exceed 72 bytes in length.'] + ['password' => 'Password cannot exceed 72 bytes in length.'], ); } @@ -110,7 +110,7 @@ public function testLoginTooLongPasswordArgon2id(): void $result->assertSessionMissing('error'); $result->assertSessionHas( 'errors', - ['password' => 'The Password field cannot exceed 255 characters in length.'] + ['password' => 'The Password field cannot exceed 255 characters in length.'], ); } diff --git a/tests/Controllers/MagicLinkTest.php b/tests/Controllers/MagicLinkTest.php index 477c98248..fce1d4600 100644 --- a/tests/Controllers/MagicLinkTest.php +++ b/tests/Controllers/MagicLinkTest.php @@ -119,7 +119,7 @@ public function testMagicLinkVerifyPendingRegistrationActivation(): void 'id' => $user->id, 'auth_action' => 'CodeIgniter\Shield\Authentication\Actions\EmailActivator', 'auth_action_message' => lang('Auth.needVerification'), - ] + ], ); $this->assertFalse(auth()->loggedIn()); } diff --git a/tests/Controllers/RegisterTest.php b/tests/Controllers/RegisterTest.php index e01b726e3..9a56f7bca 100644 --- a/tests/Controllers/RegisterTest.php +++ b/tests/Controllers/RegisterTest.php @@ -113,7 +113,7 @@ public function testRegisterTooLongPasswordDefault(): void $result->assertSessionMissing('error'); $result->assertSessionHas( 'errors', - ['password' => 'Password cannot exceed 72 bytes in length.'] + ['password' => 'Password cannot exceed 72 bytes in length.'], ); } @@ -135,7 +135,7 @@ public function testRegisterTooLongPasswordArgon2id(): void $result->assertSessionMissing('error'); $result->assertSessionHas( 'errors', - ['password' => 'The Password field cannot exceed 255 characters in length.'] + ['password' => 'The Password field cannot exceed 255 characters in length.'], ); } @@ -325,7 +325,7 @@ public function testRegisterActionWithBadEmailValue(): void $result->assertSessionMissing('error'); $result->assertSessionHas( 'errors', - ['email' => 'The Email Address field must contain a valid email address.'] + ['email' => 'The Email Address field must contain a valid email address.'], ); } diff --git a/tests/Language/AbstractTranslationTestCase.php b/tests/Language/AbstractTranslationTestCase.php index 376a48783..9edc13479 100644 --- a/tests/Language/AbstractTranslationTestCase.php +++ b/tests/Language/AbstractTranslationTestCase.php @@ -14,6 +14,7 @@ namespace Tests\Language; use CodeIgniter\CLI\CLI; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; /** @@ -100,14 +101,13 @@ abstract class AbstractTranslationTestCase extends TestCase /** * This tests that all language files configured in the main CI4 repository * have a corresponding language file in the current locale. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllConfiguredLanguageFilesAreTranslated(string $locale): void { $filesNotTranslated = array_diff( $this->expectedSets(), - $this->foundSets($locale) + $this->foundSets($locale), ); sort($filesNotTranslated); @@ -118,21 +118,20 @@ final public function testAllConfiguredLanguageFilesAreTranslated(string $locale $count > 1 ? 'files' : 'file', implode('", "', $filesNotTranslated), $count > 1 ? 'are' : 'is', - $locale + $locale, )); } /** * This tests that all translated language files in the current locale have a * corresponding language file in the main CI4 repository. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllTranslatedLanguageFilesAreConfigured(string $locale): void { $filesNotConfigured = array_diff( $this->foundSets($locale), - $this->expectedSets() + $this->expectedSets(), ); sort($filesNotConfigured); @@ -143,16 +142,15 @@ final public function testAllTranslatedLanguageFilesAreConfigured(string $locale $count > 1 ? 'files' : 'file', implode('", "', $filesNotConfigured), $locale, - $count > 1 ? 'are' : 'is' + $count > 1 ? 'are' : 'is', )); } /** * This tests that all language keys defined by a language file in the main CI4 * repository have corresponding keys in the current locale. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllConfiguredLanguageKeysAreIncluded(string $locale): void { $keysNotIncluded = []; @@ -160,7 +158,7 @@ final public function testAllConfiguredLanguageKeysAreIncluded(string $locale): foreach ($this->foundSets($locale) as $file) { $missing = array_diff_key( $this->loadFile($file), - $this->loadFile($file, $locale) + $this->loadFile($file, $locale), ); foreach (array_keys($missing) as $key) { @@ -176,16 +174,15 @@ final public function testAllConfiguredLanguageKeysAreIncluded(string $locale): $count > 1 ? 'keys' : 'key', implode('", "', $keysNotIncluded), $count > 1 ? 'are' : 'is', - $locale + $locale, )); } /** * This tests that all included language keys in a language file for the current * locale have corresponding keys in the main CI4 repository. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllIncludedLanguageKeysAreConfigured(string $locale): void { $keysNotConfigured = []; @@ -193,7 +190,7 @@ final public function testAllIncludedLanguageKeysAreConfigured(string $locale): foreach ($this->foundSets($locale) as $file) { $extra = array_diff_key( $this->loadFile($file, $locale), - $this->loadFile($file) + $this->loadFile($file), ); foreach (array_keys($extra) as $key) { @@ -209,7 +206,7 @@ final public function testAllIncludedLanguageKeysAreConfigured(string $locale): $count > 1 ? 'keys' : 'key', implode('", "', $keysNotConfigured), $locale, - $count > 1 ? 'are' : 'is' + $count > 1 ? 'are' : 'is', )); } @@ -217,9 +214,8 @@ final public function testAllIncludedLanguageKeysAreConfigured(string $locale): * This tests that all included language keys in a language file for the current * locale that have corresponding keys in the main CI4 repository are really translated * and do not only copy the main repository's value. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllIncludedLanguageKeysAreTranslated(string $locale): void { // These keys are usually not translated because they contain either @@ -256,16 +252,15 @@ final public function testAllIncludedLanguageKeysAreTranslated(string $locale): $count > 1 ? 'keys' : 'key', implode('", "', $keysNotTranslated), $locale, - $count > 1 ? 'differ' : 'differs' + $count > 1 ? 'differ' : 'differs', )); } /** * This tests that the order of all language keys defined by a translation language file * resembles the order in the main CI4 repository. - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllConfiguredLanguageKeysAreInOrder(string $locale): void { $diffs = []; @@ -287,7 +282,7 @@ final public function testAllConfiguredLanguageKeysAreInOrder(string $locale): v "\n%s:\n%s\n%s", $file, CLI::color("-'{$expectedKey}' => '{$original[$expectedKey]}';", 'red'), - CLI::color("+'{$actualKey}' => '{$translated[$actualKey]}';", 'green') + CLI::color("+'{$actualKey}' => '{$translated[$actualKey]}';", 'green'), ); break; } @@ -299,15 +294,14 @@ final public function testAllConfiguredLanguageKeysAreInOrder(string $locale): v "Failed asserting that the translated language keys in \"%s\" locale are ordered correctly.\n%s\n%s", $locale, CLI::color('--- Original', 'red') . "\n" . CLI::color('+++ Translated', 'green'), - implode("\n", $diffs) + implode("\n", $diffs), )); } /** * @see https://codeigniter4.github.io/CodeIgniter4/outgoing/localization.html#replacing-parameters - * - * @dataProvider localesProvider */ + #[DataProvider('localesProvider')] final public function testAllLocalizationParametersAreNotTranslated(string $locale): void { $diffs = []; @@ -332,7 +326,7 @@ final public function testAllLocalizationParametersAreNotTranslated(string $loca foreach ($matches as $match) { foreach ($match as $parameter) { - if (strpos($translated[$key], $parameter) === false) { + if (! str_contains($translated[$key], $parameter)) { $id = sprintf('%s.%s', substr($file, 0, -4), $key); $diffs[$id] ??= []; @@ -353,8 +347,8 @@ final public function testAllLocalizationParametersAreNotTranslated(string $loca implode("\n", array_map( static fn (string $key, array $values): string => sprintf(' * %s => %s', $key, implode(', ', $values)), array_keys($diffs), - array_values($diffs) - )) + array_values($diffs), + )), )); } @@ -372,16 +366,14 @@ final public static function localesProvider(): iterable return [$locale => [$locale]]; } - /** - * @dataProvider localesProvider - */ + #[DataProvider('localesProvider')] final public function testLocaleHasCorrespondingTestCaseFile(string $locale): void { $class = array_flip(self::$locales)[$locale]; $this->assertTrue(class_exists($class, false), sprintf( 'Failed asserting that test class "%s" is existing.', - $class + $class, )); } @@ -402,7 +394,7 @@ final public function translationKeys(): array $dirs = directory_map(getcwd() . '/Language', 1); foreach ($dirs as $dir) { - $dir = trim($dir, '\\/'); + $dir = trim((string) $dir, '\\/'); $sets[$dir] = [$dir]; } diff --git a/tests/Unit/Authentication/JWT/JWTManagerTest.php b/tests/Unit/Authentication/JWT/JWTManagerTest.php index 684281898..7e9276f3f 100644 --- a/tests/Unit/Authentication/JWT/JWTManagerTest.php +++ b/tests/Unit/Authentication/JWT/JWTManagerTest.php @@ -18,6 +18,7 @@ use CodeIgniter\Shield\Config\AuthJWT; use CodeIgniter\Shield\Entities\User; use CodeIgniter\Shield\Models\UserModel; +use PHPUnit\Framework\Attributes\Depends; use Tests\Support\TestCase; /** @@ -54,9 +55,7 @@ public function testGenerateToken() return [$token, $currentTime]; } - /** - * @depends testGenerateToken - */ + #[Depends('testGenerateToken')] public function testGenerateTokenPayload(array $data): void { [$token, $currentTime] = $data; @@ -121,9 +120,7 @@ public function testIssue() return [$token, $currentTime]; } - /** - * @depends testIssue - */ + #[Depends('testIssue')] public function testIssuePayload(array $data): void { [$token, $currentTime] = $data; @@ -259,12 +256,12 @@ private function decodeJWT(string $token, $part): array str_replace( '-', '+', - explode('.', $token)[$index] - ) + explode('.', $token)[$index], + ), ), - true + true, ), - true + true, ); } diff --git a/tests/Unit/CompositionValidatorTest.php b/tests/Unit/CompositionValidatorTest.php index 3b3bed60b..77f0df0db 100644 --- a/tests/Unit/CompositionValidatorTest.php +++ b/tests/Unit/CompositionValidatorTest.php @@ -56,7 +56,7 @@ public function testCheckFalse(): void $this->assertFalse($result->isOK()); $this->assertSame( lang('Auth.errorPasswordLength', [$this->config->minimumPasswordLength]), - $result->reason() + $result->reason(), ); } @@ -69,7 +69,7 @@ public function testCheckFalseMultibyte(): void $this->assertFalse($result->isOK()); $this->assertSame( lang('Auth.errorPasswordLength', [$this->config->minimumPasswordLength]), - $result->reason() + $result->reason(), ); } diff --git a/tests/Unit/FilterInCliTest.php b/tests/Unit/FilterInCliTest.php index ad642c657..d21ced9db 100644 --- a/tests/Unit/FilterInCliTest.php +++ b/tests/Unit/FilterInCliTest.php @@ -19,6 +19,7 @@ use CodeIgniter\Shield\Filters\ChainAuth; use CodeIgniter\Shield\Filters\SessionAuth; use CodeIgniter\Shield\Filters\TokenAuth; +use PHPUnit\Framework\Attributes\DataProvider; use Tests\Support\TestCase; /** @@ -26,9 +27,7 @@ */ final class FilterInCliTest extends TestCase { - /** - * @dataProvider provideWhenInCliDoNothing - */ + #[DataProvider('provideWhenInCliDoNothing')] public function testWhenInCliDoNothing(FilterInterface $filter): void { $clirequest = $this->createMock(CLIRequest::class); diff --git a/tests/Unit/LoginModelTest.php b/tests/Unit/LoginModelTest.php index 2d77f4cfd..96133b2d6 100644 --- a/tests/Unit/LoginModelTest.php +++ b/tests/Unit/LoginModelTest.php @@ -38,7 +38,7 @@ public function testRecordLoginAttemptThrowsException(): void $this->expectException(ValidationException::class); $this->expectExceptionMessage( 'Validation error: [ip_address] The ip_address field is required.' - . ' [id_type] The id_type field is required.' + . ' [id_type] The id_type field is required.', ); $model = $this->createLoginModel(); @@ -46,7 +46,7 @@ public function testRecordLoginAttemptThrowsException(): void $model->recordLoginAttempt( '', '', - true + true, ); } } diff --git a/tests/Unit/NothingPersonalValidatorTest.php b/tests/Unit/NothingPersonalValidatorTest.php index d5d173d36..30652de42 100644 --- a/tests/Unit/NothingPersonalValidatorTest.php +++ b/tests/Unit/NothingPersonalValidatorTest.php @@ -17,6 +17,7 @@ use CodeIgniter\Shield\Config\Auth; use CodeIgniter\Shield\Entities\User; use CodeIgniter\Test\CIUnitTestCase; +use PHPUnit\Framework\Attributes\DataProvider; /** * @internal @@ -166,12 +167,9 @@ public function testFalseForSensibleMatch(): void * rejected by isNotSimilar(). * * $config->maxSimilarity = 50; is the highest setting where all tests pass. - * - * @dataProvider provideIsNotPersonalFalsePositivesCaughtByIsNotSimilar - * - * @param mixed $password */ - public function testIsNotPersonalFalsePositivesCaughtByIsNotSimilar($password): void + #[DataProvider('provideIsNotPersonalFalsePositivesCaughtByIsNotSimilar')] + public function testIsNotPersonalFalsePositivesCaughtByIsNotSimilar(mixed $password): void { new User([ 'username' => 'CaptainJoe', @@ -203,14 +201,8 @@ public static function provideIsNotPersonalFalsePositivesCaughtByIsNotSimilar(): ]; } - /** - * @dataProvider provideConfigPersonalFieldsValues - * - * @param mixed $firstName - * @param mixed $lastName - * @param mixed $expected - */ - public function testConfigPersonalFieldsValues($firstName, $lastName, $expected): void + #[DataProvider('provideConfigPersonalFieldsValues')] + public function testConfigPersonalFieldsValues(mixed $firstName, mixed $lastName, mixed $expected): void { $config = new Auth(); $config->maxSimilarity = 66; @@ -255,18 +247,8 @@ public static function provideConfigPersonalFieldsValues(): iterable ]; } - /** - * @dataProvider provideMaxSimilarityZeroTurnsOffSimilarityCalculation - * - * The calculated similarity of 'captnjoe' and 'CaptainJoe' is 88.89. - * With $config->maxSimilarity = 66; the password should be rejected, - * but using $config->maxSimilarity = 0; will turn off the calculation - * and accept the password. - * - * @param mixed $maxSimilarity - * @param mixed $expected - */ - public function testMaxSimilarityZeroTurnsOffSimilarityCalculation($maxSimilarity, $expected): void + #[DataProvider('provideMaxSimilarityZeroTurnsOffSimilarityCalculation')] + public function testMaxSimilarityZeroTurnsOffSimilarityCalculation(mixed $maxSimilarity, mixed $expected): void { $config = new Auth(); $config->maxSimilarity = $maxSimilarity; @@ -298,9 +280,7 @@ public static function provideMaxSimilarityZeroTurnsOffSimilarityCalculation(): ]; } - /** - * @dataProvider provideCheckPasswordWithBadEmail - */ + #[DataProvider('provideCheckPasswordWithBadEmail')] public function testCheckPasswordWithBadEmail(string $email, bool $expected): void { $config = new Auth(); diff --git a/tests/Unit/PasswordsTest.php b/tests/Unit/PasswordsTest.php index 80bad8ac0..4719f8adf 100644 --- a/tests/Unit/PasswordsTest.php +++ b/tests/Unit/PasswordsTest.php @@ -17,6 +17,7 @@ use CodeIgniter\Shield\Config\Auth as AuthConfig; use CodeIgniter\Shield\Entities\User; use CodeIgniter\Test\CIUnitTestCase; +use PHPUnit\Framework\Attributes\Depends; /** * @internal @@ -55,9 +56,7 @@ public function testHash(): string return $hashedPassword; } - /** - * @depends testHash - */ + #[Depends('testHash')] public function testNeedsRehashTakesCareOptions(string $hashedPassword): void { $config = new AuthConfig(); diff --git a/tests/Unit/PwnedValidatorTest.php b/tests/Unit/PwnedValidatorTest.php index 52e5b6767..9c8c386dd 100644 --- a/tests/Unit/PwnedValidatorTest.php +++ b/tests/Unit/PwnedValidatorTest.php @@ -49,7 +49,7 @@ public function testCheckFalseOnPwnedPassword(): void '538F23AA21F516E4767380DE4AB7D30AF9B:2', '5421C6ECD4AF2B65598980DDC3BC164ED4B:9', '54355ADA7D7B306C68DAC1548E84B53A10F:1', - ] + ], ); $response = new Response(new App()); @@ -103,7 +103,7 @@ public function testCheckTrueOnNotFound(): void '0385DB23CA0658858A494B66A7933955551:1', '03B14A9EA4D383220176FDC3B3BC771A415:1', '03BE55564E0C24C43E416F595B743588A27:1', - ] + ], ); $response = new Response(new App()); @@ -133,7 +133,7 @@ public function testCheckCatchesAndRethrowsCurlExceptionAsAuthException(): void $curlrequest->method('get') ->willThrowException(HTTPException::forCurlError( '7', - 'Failed to connect' + 'Failed to connect', )); Services::injectMock('curlrequest', $curlrequest); diff --git a/tests/Unit/UserIdentityModelTest.php b/tests/Unit/UserIdentityModelTest.php index 53cbb4259..00133a98a 100644 --- a/tests/Unit/UserIdentityModelTest.php +++ b/tests/Unit/UserIdentityModelTest.php @@ -79,7 +79,7 @@ public function testCreateCodeIdentityThrowsExceptionIfUniqueCodeIsNotGot(): voi 'name' => 'register', 'extra' => lang('Auth.needVerification'), ], - $generator + $generator, ); } diff --git a/tests/Unit/UserTest.php b/tests/Unit/UserTest.php index 9c4d3ccda..2f6d7a440 100644 --- a/tests/Unit/UserTest.php +++ b/tests/Unit/UserTest.php @@ -118,7 +118,7 @@ public function testModelFindAllWithIdentitiesWhereInQuery(): void $this->assertMatchesRegularExpression( '/WHERE\s+.*\s+IN\s+\([^)]+\)/i', $query, - 'Identities were not obtained with the single query (missing "WHERE ... IN" condition)' + 'Identities were not obtained with the single query (missing "WHERE ... IN" condition)', ); } @@ -136,7 +136,7 @@ public function testLastLogin(): void { fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD, 'secret' => 'foo@example.com'] + ['user_id' => $this->user->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD, 'secret' => 'foo@example.com'], ); // No logins found. @@ -144,11 +144,11 @@ public function testLastLogin(): void fake( LoginModel::class, - ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id] + ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id], ); $login2 = fake( LoginModel::class, - ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id] + ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id], ); fake( LoginModel::class, @@ -157,7 +157,7 @@ public function testLastLogin(): void 'identifier' => $this->user->email, 'user_id' => $this->user->id, 'success' => false, - ] + ], ); $last = $this->user->lastLogin(); @@ -171,7 +171,7 @@ public function testPreviousLogin(): void { fake( UserIdentityModel::class, - ['user_id' => $this->user->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD, 'secret' => 'foo@example.com'] + ['user_id' => $this->user->id, 'type' => Session::ID_TYPE_EMAIL_PASSWORD, 'secret' => 'foo@example.com'], ); // No logins found. @@ -179,7 +179,7 @@ public function testPreviousLogin(): void $login1 = fake( LoginModel::class, - ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id] + ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id], ); // The very most login is skipped. @@ -187,7 +187,7 @@ public function testPreviousLogin(): void fake( LoginModel::class, - ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id] + ['id_type' => 'email', 'identifier' => $this->user->email, 'user_id' => $this->user->id], ); fake( LoginModel::class, @@ -196,7 +196,7 @@ public function testPreviousLogin(): void 'identifier' => $this->user->email, 'user_id' => $this->user->id, 'success' => false, - ] + ], ); $previous = $this->user->previousLogin();