myth-auth icon indicating copy to clipboard operation
myth-auth copied to clipboard

Exception in json post!

Open rafinhaa opened this issue 3 years ago • 8 comments

Hi, i implemented myth auth in a test api and when i try to create a new user via "application/json" i get an exception

{
  "title": "ErrorException",
  "type": "ErrorException",
  "code": 500,
  "message": "Undefined offset: 1",
  "file": "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/NothingPersonalValidator.php",
  "line": 90,
  "trace": [
    {
      "file": "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/NothingPersonalValidator.php",
      "line": 90,
      "function": "errorHandler",
      "class": "CodeIgniter\\Debug\\Exceptions",
      "type": "->",
      "args": [
        8,
        "Undefined offset: 1",
        "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/NothingPersonalValidator.php",
        90,
        {
          "password": "[email protected]",
          "user": [],
          "userName": "",
          "email": "",
          "valid": true,
          "needles": [
            ""
          ],
          "localPart": ""
        }
      ]
    },
    {
      "file": "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/NothingPersonalValidator.php",
      "line": 39,
      "function": "isNotPersonal",
      "class": "Myth\\Auth\\Authentication\\Passwords\\NothingPersonalValidator",
      "type": "->",
      "args": [
        "[email protected]",
        []
      ]
    },
    {
      "file": "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/PasswordValidator.php",
      "line": 55,
      "function": "check",
      "class": "Myth\\Auth\\Authentication\\Passwords\\NothingPersonalValidator",
      "type": "->",
      "args": [
        "[email protected]",
        []
      ]
    },
    {
      "file": "/var/www/html/vendor/myth/auth/src/Authentication/Passwords/ValidationRules.php",
      "line": 45,
      "function": "check",
      "class": "Myth\\Auth\\Authentication\\Passwords\\PasswordValidator",
      "type": "->",
      "args": [
        "[email protected]",
        []
      ]
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/Validation/Validation.php",
      "line": 312,
      "function": "strong_password",
      "class": "Myth\\Auth\\Authentication\\Passwords\\ValidationRules",
      "type": "->",
      "args": [
        "[email protected]",
        null
      ]
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/Validation/Validation.php",
      "line": 159,
      "function": "processRules",
      "class": "CodeIgniter\\Validation\\Validation",
      "type": "->",
      "args": [
        "password",
        "password",
        "[email protected]",
        [
          "required",
          "strong_password"
        ],
        {
          "name": "rafael",
          "lastname": "sonicne",
          "email": "[email protected]",
          "password": "[email protected]",
          "cpassword": "[email protected]",
          "DBGroup": null
        }
      ]
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/Controller.php",
      "line": 183,
      "function": "run",
      "class": "CodeIgniter\\Validation\\Validation",
      "type": "->",
      "args": []
    },
    {
      "file": "/var/www/html/app/Controllers/Api/V1/Users.php",
      "line": 99,
      "function": "validate",
      "class": "CodeIgniter\\Controller",
      "type": "->",
      "args": [
        {
          "email": {
            "rules": "required|valid_email|is_unique[users.email]",
            "errors": {
              "required": "O e-mail é necessário",
              "valid_email": "Você deve inserir um email válido",
              "is_unique": "Esse e-mail já está cadastrado"
            }
          },
          "name": {
            "rules": "required|min_length[2]",
            "errors": {
              "required": "Seu nome é necessário",
              "min_length": "Seu nome deve ter pelo menos 2 caracteres"
            }
          },
          "lastname": {
            "rules": "required|min_length[2]",
            "errors": {
              "required": "Seu sobrenome é necessário",
              "min_length": "Seu sobrenome deve ter pelo menos 2 caracteres"
            }
          },
          "password": {
            "rules": "required|strong_password",
            "errors": {
              "required": "A senha é necessário",
              "strong_password": "Essa senha está facil demais"
            }
          },
          "cpassword": {
            "rules": "required|matches[password]",
            "errors": {
              "required": "Você não digitou a confirmação da senha",
              "matches": "As senhas não são iguais"
            }
          }
        }
      ]
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/CodeIgniter.php",
      "line": 928,
      "function": "create",
      "class": "App\\Controllers\\Api\\V1\\Users",
      "type": "->",
      "args": []
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/CodeIgniter.php",
      "line": 436,
      "function": "runController",
      "class": "CodeIgniter\\CodeIgniter",
      "type": "->",
      "args": [
        {}
      ]
    },
    {
      "file": "/var/www/html/vendor/codeigniter4/framework/system/CodeIgniter.php",
      "line": 336,
      "function": "handleRequest",
      "class": "CodeIgniter\\CodeIgniter",
      "type": "->",
      "args": [
        null,
        {
          "handler": "file",
          "backupHandler": "dummy",
          "storePath": "/var/www/html/writable/cache/",
          "cacheQueryString": false,
          "prefix": "",
          "ttl": 60,
          "file": {
            "storePath": "/var/www/html/writable/cache/",
            "mode": 416
          },
          "memcached": {
            "host": "127.0.0.1",
            "port": 11211,
            "weight": 1,
            "raw": false
          },
          "redis": {
            "host": "127.0.0.1",
            "password": null,
            "port": 6379,
            "timeout": 0,
            "database": 0
          },
          "validHandlers": {
            "dummy": "CodeIgniter\\Cache\\Handlers\\DummyHandler",
            "file": "CodeIgniter\\Cache\\Handlers\\FileHandler",
            "memcached": "CodeIgniter\\Cache\\Handlers\\MemcachedHandler",
            "predis": "CodeIgniter\\Cache\\Handlers\\PredisHandler",
            "redis": "CodeIgniter\\Cache\\Handlers\\RedisHandler",
            "wincache": "CodeIgniter\\Cache\\Handlers\\WincacheHandler"
          }
        },
        false
      ]
    },
    {
      "file": "/var/www/html/public/index.php",
      "line": 37,
      "function": "run",
      "class": "CodeIgniter\\CodeIgniter",
      "type": "->",
      "args": []
    }
  ]
}

When I send the request through "multipart/form-data" I get the registration successfully!

I investigated the myth files to find a solution to this problem, but I couldn't.

Below are the classes I used as a test:

<?php

namespace App\Controllers\Api\V1;

use CodeIgniter\RESTful\ResourceController;

class Users extends ResourceController
{
    protected $modelName = 'App\Models\UserModel';
    protected $format    = 'json';

	public function create(){
		$rules = [
			'email' => [
				'rules' => 'required|valid_email|is_unique[users.email]',				
				'errors' => [
					'required' => 'O e-mail é necessário',
					'valid_email' => 'Você deve inserir um email válido',
					'is_unique' => 'Esse e-mail já está cadastrado',
				],
			],
			'name' => [
				'rules' => 'required|min_length[2]',
				'errors' => [
					'required' => 'Seu nome é necessário',
					'min_length' => 'Seu nome deve ter pelo menos 2 caracteres',
				],
			],
			'lastname' => [
				'rules' => 'required|min_length[2]',
				'errors' => [
					'required' => 'Seu sobrenome é necessário',
					'min_length' => 'Seu sobrenome deve ter pelo menos 2 caracteres',
				],
			],
			'password' => [
				'rules' => 'required|strong_password',
				'errors' => [
					'required' => 'A senha é necessário',
					'strong_password' => 'Essa senha está facil demais',
				],                
			],			
			'cpassword' => [
				'rules' => 'required|matches[password]',
				'errors' => [
					'required' => 'Você não digitou a confirmação da senha',
					'matches' => 'As senhas não são iguais',
				],                
			],
		];

		if (! $this->validate($rules)){
			return $this->respond([
				'status' => 500,
				'error' => true,
				'message' => $this->validator->getErrors(),
				'data' => []
			],500);
		}
        die('registration ok');
	}


}

Routes: $routes->resource('api/v1/users');

Prints: fail ok

Codeigniter 4.1.3 PHP 7.3

rafinhaa avatar Aug 30 '21 18:08 rafinhaa

I found the cause of the problem, I had to modify the buildUserFromRequest method in the /src/Authentication/Passwords/ValidationRules.php file

protected function buildUserFromRequest()
{
    $fields = $this->prepareValidFields();

    if (strpos(service('request')->getHeaderLine('Content-Type'), 'application/json') !== false)
    {
        $data = (array) service('request')->getJSON();
	$data = array_intersect_key($data, array_fill_keys($fields, null));
    }else{
        $data = array_filter(service('request')->getPost($fields));
    }
    return new User($data);
}

Is this modification acceptable?

rafinhaa avatar Aug 31 '21 19:08 rafinhaa

protected function buildUserFromRequest()
{
    $fields = $this->prepareValidFields();

    $data = array_filter(service('request')->getPost($fields));
    if (empty($data)) {
        //convert request body to associative array
        $data = array_intersect_key(
            json_decode(service('request')->getBody(), true), 
            array_fill_keys($fields, null)
        );
    }
    return new User($data);
}

so it should be better!

rafinhaa avatar Sep 01 '21 15:09 rafinhaa

I think that is likely fine. If you can submit a PR for it, that would be awesome.

lonnieezell avatar Sep 02 '21 03:09 lonnieezell

Hi, no news about adding this issue to the release?

Sparking2 avatar May 31 '22 01:05 Sparking2

If someone wants to take this on as a PR please do.

MGatner avatar Jul 12 '22 20:07 MGatner

I'll do

manageruz avatar Aug 02 '22 06:08 manageruz

Maybe just like this?

protected function buildUserFromRequest()
 {
        $fields = $this->prepareValidFields();

        // $data = array_filter(service('request')->getPost($fields));
       
        // pulling data from $_REQUEST, get rid of NULL values
        // works fine with both 'form-multipart' and 'application/json' content-types
        // return type is array
        $data = array_filter(service('request')->getVar($fields));

        return new User($data);
 }

manageruz avatar Aug 14 '22 11:08 manageruz

And what about Shield? Shield's code is same as Myth.

manageruz avatar Aug 14 '22 11:08 manageruz