Skip to content

Bug: Cannot assign bool to property CodeIgniter\Shield\Result::$reason #851

@mshannaq

Description

@mshannaq

PHP Version

8.2

CodeIgniter4 Version

4.4.1

Shield Version

dev-develop

Which operating systems have you tested for this bug?

Linux

Which server did you use?

apache

Database

mysql

Did you customize Shield?

No

What happened?

IF using another language rather that english for example 'ar' language and try to register account with not secuered password for example testpassword

I got an error which is

Cannot assign bool to property CodeIgniter\Shield\Result::$reason of type ?string [search →](https://www.duckduckgo.com/?q=TypeError+Cannot+assign+bool+to+property+CodeIgniter%5CShield%5CResult%3A%3A%24reason+of+type+%3Fstring)

instead if showing the error The password testpassword has been exposed due to a data breach and has been seen 1,109 times in databases of compromised passwords. if the ci language is english.

trace:

VENDORPATH/codeigniter4/shield/src/Result.php at line 36

* @psalm-param array{success: bool, reason?: string|null, extraInfo?: string|User} $details
30      */
31     public function __construct(array $details)
32     {
33         foreach ($details as $key => $value) {
34             assert(property_exists($this, $key), 'Property "' . $key . '" does not exist.');
35 
36             $this->{$key} = $value;
37         }
38     }
39 
40     /**
41      * Was the result a success?
42      */
43     public function isOK(): bool

Backtrack:

  1. VENDORPATH/codeigniter4/shield/src/Authentication/Passwords/PwnedValidator.php : 73 — CodeIgniter\Shield\Result->__construct ()
     $hits   = $endPos !== false ? (int) substr($range, $startPos, $endPos - $startPos) : (int) substr($range, $startPos);
67 
68         $wording = $hits > 1 ? 'databases' : 'a database';
69 
70         return new Result([
71             'success'   => false,
72             'reason'    => lang('Auth.errorPasswordPwned', [$password, $hits, $wording]),
73             'extraInfo' => lang('Auth.suggestPasswordPwned', [$password]),
74         ]);
75     }
76 }
77
  1. VENDORPATH/codeigniter4/shield/src/Authentication/Passwords.php : 132 — CodeIgniter\Shield\Authentication\Passwords\PwnedValidator->check ()
125             ]);
126         }
127 
128         foreach ($this->config->passwordValidators as $className) {
129             /** @var ValidatorInterface $class */
130             $class = new $className($this->config);
131 
132             $result = $class->check($password, $user);
133             if (! $result->isOk()) {
134                 return $result;
135             }
136         }
137 
138         return new Result([
139             'success' => true,


  1. VENDORPATH/codeigniter4/shield/src/Authentication/Passwords/ValidationRules.php : 46 — CodeIgniter\Shield\Authentication\Passwords->check ()
39         if (function_exists('auth') && auth()->user()) {
40             $user = auth()->user();
41         } else {
42             /** @phpstan-ignore-next-line */
43             $user = empty($data) ? $this->buildUserFromRequest() : $this->buildUserFromData($data);
44         }
45 
46         $result = $checker->check($value, $user);
47 
48         if (! $result->isOk()) {
49             if (empty($data)) {
50                 $error1 = $result->reason();
51             } else {
52                 $error2 = $result->reason();
53             }
  1. SYSTEMPATH/Validation/Validation.php : 309 — CodeIgniter\Shield\Authentication\Passwords\ValidationRules->strong_password ()
302                     if (! method_exists($set, $rule)) {
303                         continue;
304                     }
305 
306                     $found  = true;
307                     $passed = $param === false
308                         ? $set->{$rule}($value, $error)
309                         : $set->{$rule}($value, $param, $data, $error, $field);
310 
311                     break;
312                 }
313 
314                 // If the rule wasn't found anywhere, we
315                 // should throw an exception so the developer can find it.
316                 if (! $found) {
  1. SYSTEMPATH/Validation/Validation.php : 195 — CodeIgniter\Validation\Validation->processRules ()
188             if (strpos($field, '*') !== false) {
189                 // Process multiple fields
190                 foreach ($values as $dotField => $value) {
191                     $this->processRules($dotField, $setup['label'] ?? $field, $value, $rules, $data, $field);
192                 }
193             } else {
194                 // Process single field
195                 $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data);
196             }
197         }
198 
199         if ($this->getErrors() === []) {
200             // Store data that was actually validated.
201             $this->validated = DotArrayFilter::run(
202                 array_keys($this->rules),
  1. SYSTEMPATH/Controller.php : 165 — CodeIgniter\Validation\Validation->run ()
158      * @param array        $messages An array of custom error messages
159      * @param string|null  $dbGroup  The database group to use
160      */
161     protected function validateData(array $data, $rules, array $messages = [], ?string $dbGroup = null): bool
162     {
163         $this->setValidator($rules, $messages);
164 
165         return $this->validator->run($data, null, $dbGroup);
166     }
167 
168     /**
169      * @param array|string $rules
170      */
171     private function setValidator($rules, array $messages): void
172     {
  1. VENDORPATH/codeigniter4/shield/src/Controllers/RegisterController.php : 103 — CodeIgniter\Controller->validateData ()
96 
 97         $users = $this->getUserProvider();
 98 
 99         // Validate here first, since some things,
100         // like the password, can only be validated properly here.
101         $rules = $this->getValidationRules();
102 
103         if (! $this->validateData($this->request->getPost(), $rules, [], config('Auth')->DBGroup)) {
104             return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
105         }
106 
107         // Save the user
108         $allowedPostFields = array_keys($rules);
109         $user              = $this->getUserEntity();
110         $user->fill($this->request->getPost($allowedPostFields));
  1. SYSTEMPATH/CodeIgniter.php : 919 — CodeIgniter\Shield\Controllers\RegisterController->registerAction ()
912     protected function runController($class)
913     {
914         // This is a Web request or PHP CLI request
915         $params = $this->router->params();
916 
917         $output = method_exists($class, '_remap')
918             ? $class->_remap($this->method, ...$params)
919             : $class->{$this->method}(...$params);
920 
921         $this->benchmark->stop('controller');
922 
923         return $output;
924     }
925 
926     /**
  1. SYSTEMPATH/CodeIgniter.php : 494 — CodeIgniter\CodeIgniter->runController ()
487             if (! method_exists($controller, '_remap') && ! is_callable([$controller, $this->method], false)) {
488                 throw PageNotFoundException::forMethodNotFound($this->method);
489             }
490 
491             // Is there a "post_controller_constructor" event?
492             Events::trigger('post_controller_constructor');
493 
494             $returned = $this->runController($controller);
495         } else {
496             $this->benchmark->stop('controller_constructor');
497             $this->benchmark->stop('controller');
498         }
499 
500         // If $returned is a string, then the controller output something,
501         // probably a view, instead of echoing it directly. Send it along
  1. SYSTEMPATH/CodeIgniter.php : 353 — CodeIgniter\CodeIgniter->handleRequest ()
346 
347         $this->getRequestObject();
348         $this->getResponseObject();
349 
350         $this->spoofRequestMethod();
351 
352         try {
353             $this->response = $this->handleRequest($routes, config(Cache::class), $returnResponse);
354         } catch (ResponsableInterface|DeprecatedRedirectException $e) {
355             $this->outputBufferingEnd();
356             if ($e instanceof DeprecatedRedirectException) {
357                 $e = new RedirectException($e->getMessage(), $e->getCode(), $e);
358             }
359 
360             $this->response = $e->getResponse();
  1. FCPATH/index.php : 79 — CodeIgniter\CodeIgniter->run ()
72  *---------------------------------------------------------------
73  * LAUNCH THE APPLICATION
74  *---------------------------------------------------------------
75  * Now that everything is set up, it's time to actually fire
76  * up the engines and make this app do its thang.
77  */
78 
79 $app->run();
80 
81 // Save Config Cache
82 // $factoriesCache->save('config');
83 // ^^^ Uncomment this line if you want to use Config Caching.
84 
85 // Exits the application, setting the exit code for CLI-based applications
86 // that might be watching.

Steps to Reproduce

change ci langaue to any other language rather than english - for example arabic

try to register a new user with easy password eg testpassword

Expected Output

the correctt is return ti register form with error The password testpassword has been exposed due to a data breach and has been seen 1,109 times in databases of compromised passwords.

Anything else?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions