From 49691bc30a51973b8943217b1082562e4f0f7cd4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 29 Mar 2024 08:29:07 +0900 Subject: [PATCH 1/4] fix: Can't create new users via CLI if username is disabled --- src/Commands/User.php | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Commands/User.php b/src/Commands/User.php index 1a894d7f3..b43466ece 100644 --- a/src/Commands/User.php +++ b/src/Commands/User.php @@ -220,7 +220,7 @@ private function setValidationRules(): void $rules = $validationRules->getRegistrationRules(); - // Remove `strong_password` because it only supports use cases + // Remove `strong_password` rule because it only supports use cases // to check the user's own password. $passwordRules = $rules['password']['rules']; if (is_string($passwordRules)) { @@ -241,11 +241,10 @@ private function setValidationRules(): void $rules['password']['rules'] = $passwordRules; - $this->validationRules = [ - 'username' => $rules['username'], - 'email' => $rules['email'], - 'password' => $rules['password'], - ]; + // Remove `password_confirm` field. + unset($rules['password_confirm']); + + $this->validationRules = $rules; } /** @@ -258,10 +257,13 @@ private function create(?string $username = null, ?string $email = null): void { $data = []; - if ($username === null) { + if ($username === null && isset($this->validationRules['username'])) { $username = $this->prompt('Username', null, $this->validationRules['username']['rules']); } $data['username'] = $username; + if ($username === null) { + unset($data['username']); + } if ($email === null) { $email = $this->prompt('Email', null, $this->validationRules['email']['rules']); From 1e3ad4afa115c5175ec5e8dcc4b4d4dc6a8f49a8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 29 Mar 2024 21:24:37 +0900 Subject: [PATCH 2/4] fix: use allowEmptyInserts() when username is not used --- src/Commands/User.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Commands/User.php b/src/Commands/User.php index b43466ece..4f612f563 100644 --- a/src/Commands/User.php +++ b/src/Commands/User.php @@ -257,6 +257,7 @@ private function create(?string $username = null, ?string $email = null): void { $data = []; + // If you don't use `username`, remove the validation rules for it. if ($username === null && isset($this->validationRules['username'])) { $username = $this->prompt('Username', null, $this->validationRules['username']['rules']); } @@ -301,7 +302,12 @@ private function create(?string $username = null, ?string $email = null): void $userModel = model(UserModel::class); $user = new UserEntity($data); - $userModel->save($user); + + if ($username === null) { + $userModel->allowEmptyInserts()->save($user); + } else { + $userModel->save($user); + } $this->write('User "' . $username . '" created', 'green'); } From ca826ff3a70789b51ddd7456cd808b04fa84b2ed Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 29 Mar 2024 22:04:31 +0900 Subject: [PATCH 3/4] chore: vendor/bin/phpstan analyze --generate-baseline phpstan-baseline.php --- phpstan-baseline.php | 129 +++++++++++++++++++++++++------------------ 1 file changed, 75 insertions(+), 54 deletions(-) diff --git a/phpstan-baseline.php b/phpstan-baseline.php index c9817e23f..65f52c677 100644 --- a/phpstan-baseline.php +++ b/phpstan-baseline.php @@ -8,12 +8,12 @@ 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; $ignoreErrors[] = [ - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', 'count' => 2, 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 2, 'path' => __DIR__ . '/src/Authentication/Actions/Email2FA.php', ]; @@ -33,6 +33,16 @@ 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authentication.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', +]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 4, @@ -46,70 +56,70 @@ $ignoreErrors[] = [ 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', 'count' => 1, - 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', + 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', ]; $ignoreErrors[] = [ 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', 'count' => 1, - 'path' => __DIR__ . '/src/Authentication/Authenticators/AccessTokens.php', + 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', ]; $ignoreErrors[] = [ - '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\\(\\)$#', + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - '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\\(\\)$#', + '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\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', + '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\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/JWT.php', ]; $ignoreErrors[] = [ - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 3, + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in an elseif condition, string\\|null given\\.$#', + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\RememberModel\\:\\:class is discouraged\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in an if condition, CodeIgniter\\\\Shield\\\\Entities\\\\UserIdentity\\|null given\\.$#', + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in an if condition, int\\|string\\|null given\\.$#', + 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 3, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - '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\\(\\)$#', + 'message' => '#^Only booleans are allowed in an elseif condition, string\\|null given\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - '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\\(\\)$#', + 'message' => '#^Only booleans are allowed in an if condition, CodeIgniter\\\\Shield\\\\Entities\\\\UserIdentity\\|null given\\.$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', - 'count' => 1, + 'message' => '#^Only booleans are allowed in an if condition, int\\|string\\|null given\\.$#', + 'count' => 3, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\RememberModel\\:\\:class is discouraged\\.$#', + '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\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + '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\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/src/Authentication/Authenticators/Session.php', ]; @@ -158,6 +168,11 @@ 'count' => 1, 'path' => __DIR__ . '/src/Collectors/Auth.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:class is discouraged\\.$#', + 'count' => 9, + 'path' => __DIR__ . '/src/Commands/User.php', +]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 1, @@ -175,13 +190,13 @@ 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', - 'count' => 2, + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'count' => 1, 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', - 'count' => 1, + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'count' => 2, 'path' => __DIR__ . '/src/Controllers/MagicLinkController.php', ]; $ignoreErrors[] = [ @@ -240,13 +255,18 @@ 'path' => __DIR__ . '/src/Entities/Group.php', ]; $ignoreErrors[] = [ - 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', - 'count' => 8, + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#', + 'count' => 2, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, max\\> given\\.$#', - 'count' => 1, + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', + 'count' => 2, + 'path' => __DIR__ . '/src/Entities/User.php', +]; +$ignoreErrors[] = [ + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\PermissionModel\\:\\:class is discouraged\\.$#', + 'count' => 2, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ @@ -255,14 +275,14 @@ 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:class is discouraged\\.$#', - 'count' => 2, + 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', + 'count' => 8, 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserModel\\:\\:class is discouraged\\.$#', - 'count' => 9, - 'path' => __DIR__ . '/src/Commands/User.php', + 'message' => '#^Only booleans are allowed in a ternary operator condition, int\\<0, max\\> given\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Entities/User.php', ]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', @@ -289,6 +309,11 @@ 'count' => 2, 'path' => __DIR__ . '/src/Filters/TokenAuth.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Property CodeIgniter\\\\Shield\\\\Models\\\\LoginModel\\:\\:\\$validationRules \\(list\\\\|string\\) does not accept default value of type array\\{ip_address\\: \'required\', id_type\\: \'required\', identifier\\: \'permit_empty\\|string\', user_agent\\: \'permit_empty\\|string\', user_id\\: \'permit_empty\', date\\: \'required\'\\}\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Models/LoginModel.php', +]; $ignoreErrors[] = [ 'message' => '#^Call to deprecated function random_string\\(\\)\\: The type \'basic\', \'md5\', and \'sha1\' are deprecated\\. They are not cryptographically secure\\.$#', @@ -301,19 +326,34 @@ 'count' => 1, 'path' => __DIR__ . '/src/Models/UserIdentityModel.php', ]; +$ignoreErrors[] = [ + 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Models/UserModel.php', +]; $ignoreErrors[] = [ 'message' => '#^Construct empty\\(\\) is not allowed\\. Use more strict comparison\\.$#', 'count' => 2, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', + '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\\(\\)$#', 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ - '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\\(\\)\\$#', - 'count' => 4, + '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\\(\\)$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Models/UserModel.php', +]; +$ignoreErrors[] = [ + '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\\(\\)$#', + 'count' => 1, + 'path' => __DIR__ . '/src/Models/UserModel.php', +]; +$ignoreErrors[] = [ + '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\\(\\)$#', + 'count' => 1, 'path' => __DIR__ . '/src/Models/UserModel.php', ]; $ignoreErrors[] = [ @@ -366,24 +406,5 @@ 'count' => 1, 'path' => __DIR__ . '/tests/Unit/UserTest.php', ]; -$ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\TokenLoginModel\\:\\:class is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\UserIdentityModel\\:\\:class is discouraged\\.$#', - 'count' => 1, - 'path' => __DIR__ . '/src/Authentication/Authenticators/HmacSha256.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\GroupModel\\:\\:class is discouraged\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/src/Authorization/Traits/Authorizable.php', -]; -$ignoreErrors[] = [ - 'message' => '#^Call to function model with CodeIgniter\\\\Shield\\\\Models\\\\PermissionModel\\:\\:class is discouraged\\.$#', - 'count' => 2, - 'path' => __DIR__ . '/src/Authorization/Traits/Authorizable.php', -]; + return ['parameters' => ['ignoreErrors' => $ignoreErrors]]; From 3aa3b19845615f1e14f01647ab15e7cdc8a25797 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 4 Apr 2024 09:17:54 +0900 Subject: [PATCH 4/4] fix: output appropriate message --- src/Commands/User.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Commands/User.php b/src/Commands/User.php index 4f612f563..0a332ffc8 100644 --- a/src/Commands/User.php +++ b/src/Commands/User.php @@ -305,11 +305,11 @@ private function create(?string $username = null, ?string $email = null): void if ($username === null) { $userModel->allowEmptyInserts()->save($user); + $this->write('New User created', 'green'); } else { $userModel->save($user); + $this->write('User "' . $username . '" created', 'green'); } - - $this->write('User "' . $username . '" created', 'green'); } /**