Extending IonAuth model, language files from the third party folder - Codeigniter4

327 Views Asked by At

IonAuth is running in the ThirdParty folder on Codeigniter4. I have extended the controller, in that I have Auth.php running in my app/Controllers directory and that is working.

How can I extend the IonAuth library, the model and the language files etc? These files get ignored, unlike the Auth.php controller. I don't want to edit the files in the ThirdParty folder, to make it easier to upgrade etc. Thanks.

2

There are 2 best solutions below

0
paliz On

look at my code do it like me follow my approach ctl auth

<?php namespace Modules\Auth\Controllers;


use Modules\Auth\Config\ModuleAuthConfig;
use Modules\Auth\Config\Services;
use Modules\Auth\Entities\AuthEntity;
use Modules\Auth\Enums\RoleType;
use Modules\Auth\Interfaces\AuthControllerInterface;
use Modules\Shared\Config\ModuleSharedConfig;
use Modules\Shared\Controllers\BaseController;
use Modules\Shared\Enums\NotificationType;

use CodeIgniter\HTTP\ResponseInterface;
use Myth\Auth\AuthTrait;
use Pusher\Pusher;
use ReCaptcha\ReCaptcha;

class Auth extends BaseController implements AuthControllerInterface
{
    use AuthTrait;


    public function signInJwt(): ResponseInterface
    {


        /**
         * Attempts to verify the user's credentials
         * through a POST request.
         */
        $rules = [
            'login' => 'required',
            'password' => 'required'

        ];

        $config = config('Myth\Auth\Config\Auth');

        if ($config->validFields == ['email']) {
            $rules['login'] .= '|valid_email';
        };


        if (!$this->validate($rules)) {


            return $this->response->setJSON(['error' => $this->validator->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }

        $authEntity = new AuthEntity((array)$this->request->getVar());

        $authEntity->logInMode()->loginDate()->ipAddress($this->request->getIPAddress());


        $authService = Services::authService();
        $data = $authService->signInJwt($authEntity);
        $authConfig = new  ModuleAuthConfig();

        return $this->response->setHeader($authConfig->jwt['name'], $data['jwt']['token'])
            ->setCookie($authConfig->jwt['name'], $data['jwt']['token'], $data['jwt']['expire'])->
            setJSON($data)->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.logIn'))
            ->setContentType('application/json');


    }

    public function signIn(): ResponseInterface
    {


        $this->setupAuthClasses();


        /**
         * Attempts to verify the user's credentials
         * through a POST request.
         */
        $rules = [
            'login' => 'required',
            'password' => 'required'

        ];

        $config = config('Myth\Auth\Config\Auth');

        if ($config->validFields == ['email']) {
            $rules['login'] .= '|valid_email';
        };


        if (!$this->validate($rules)) {


            return $this->response->setJSON(['error' => $this->validator->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }


        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->logInMode();


        $remember = $authEntity->remember ?? false;

        if (!$this->authenticate->attempt([$authEntity->loginType => $authEntity->login, 'password' => $authEntity->password], $remember)) {


            return $this->response->setJSON(['error' => $this->authenticate->error(),
            ])
                ->setStatusCode(ResponseInterface::HTTP_UNAUTHORIZED, lang('Auth.badAttempt'))
                ->setContentType('application/json');

        }

        // Is the user being forced to reset their password?
        if ($this->authenticate->user()->force_pass_reset === true) {

            //  return redirect()->to(route_to('reset-password') . '?token=' . $this->auth->user()->reset_hash)->withCookies();
            return $this->response->setJSON(['token' => $this->authenticate->user()->reset_hash])
                ->setStatusCode(ResponseInterface::HTTP_UNAUTHORIZED, lang('Authenticate.auth.foreResetPassword'))
                ->setContentType('application/json');

        }

        $authService = Services::authService();
        $data = $authService->signIn($authEntity);


        return $this->response->setJSON(
            $data
        )->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.logIn'))
            ->setContentType('application/json');


    }


    /**
     * Log the user out.
     */
    public function signOut(): ResponseInterface
    {

        $this->setupAuthClasses();
        $authConfig = new  ModuleAuthConfig();

        $jwtHeader = $this->request->getServer('HTTP_AUTHORIZATION');
        $jwtCookie = $this->request->getCookie($authConfig->jwt['name']);


        if ($this->authenticate->check()) {
            $this->authenticate->logout();
        } else if (!is_null($jwtHeader) || !is_null($jwtCookie)) {


            $authService = Services::authService();

            $requestWithUser = Services::requestWithUser();
            $authService->signOutJwt($requestWithUser->getUser());

            $this->response->setHeader($authConfig->jwt['name'], '');
            $this->response->setCookie($authConfig->jwt['name'], '', 0);

        }

        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.logOut'))
            ->setContentType('application/json');


    }

    /**
     * Log the user out.
     */
    public function isSignIn(): ResponseInterface
    {

        $this->setupAuthClasses();
        $requestWithUser = Services::requestWithUser();

        if ($this->authenticate->check() || isset($requestWithUser->getUser()->id)) {

            return $this->response->setJSON(['success' => true])
                ->setStatusCode(ResponseInterface::HTTP_OK, lang('check is sign in'))
                ->setContentType('application/json');
        } else {
            return $this->response->setJSON(['success' => false,
            ])
                ->setStatusCode(ResponseInterface::HTTP_OK, lang('check is sign in'))
                ->setContentType('application/json');
        }


    }


    //--------------------------------------------------------------------
    // Register
    //--------------------------------------------------------------------

    /**
     * Displays the user registration page.
     */
    public function signUp(): ResponseInterface
    {


        $throttler = \Codeigniter\Config\Services::throttler();

        if ($throttler->check($this->request->getIPAddress(), 5, MINUTE) === false) {

            return $this->response->setJSON(['data' => $throttler->getTokentime()])
                ->setStatusCode(ResponseInterface::HTTP_TOO_MANY_REQUESTS, lang('Auth.tooManyRequests', [$throttler->getTokentime()]))
                ->setContentType('application/json');

        }

        // Validate here first, since some things,
        // like the password, can only be validated properly here.
        // strong password didint work custom validation  strong_password
        // password=> strong_password
        helper('authentication');

        if (loginVia($this->request->getVar('login') ?? $this->request->getVar('login')) == 'email') {

            $lineRule = 'required|valid_email|is_unique[users.email]';
        } else if (loginVia($this->request->getVar('login') ?? $this->request->getVar('login')) == 'phone') {

            $lineRule = 'required|min_length[9]|is_unique[users.phone]';
        } else {

            return $this->response->setJSON(['error' => lang('Authenticate.auth.emailOrPhone')])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }

        $rules = [
            'username' => 'required|alpha_numeric_space|min_length[3]|is_unique[users.username]',
            'login' => $lineRule,
            'password' => 'required|min_length[6]',
            'passConfirm' => 'required|matches[password]',
            'action' => 'required',
            'token' => 'required',
            'socialLogin' => 'required'

        ];

        if (!$this->validate($rules)) {

            return $this->response->setJSON([

                'error' => service('validation')->getErrors(),
            ])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');

        }


        $authConfig = new  \Modules\Auth\Config\ModuleAuthConfig();
        // ->setExpectedHostname($_SERVER['SERVER_NAME'])
        $recaptcha = new ReCaptcha($authConfig->captcha['secretKey']);
        $resp = $recaptcha->setExpectedAction($this->request->getVar('action'))
            ->setScoreThreshold(0.2)
            ->verify($this->request->getVar('token'), $_SERVER['REMOTE_ADDR']);
        // verify the response
        if (!$resp->isSuccess() && !$this->request->getVar('socialLogin')) {
            // spam submission
            // show error message
            return $this->response->setJSON([
                'error' => $resp->getErrorCodes()])
                ->setStatusCode(ResponseInterface:: HTTP_UNAUTHORIZED, lang('Authenticate.auth.captchaError'))
                ->setContentType('application/json');
        }
        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->logInMode()->createdAt()->setRole(RoleType::Member);
        unset($authEntity->token);
        unset($authEntity->action);
        $authService = Services::authService();
        $authService->signUp($authEntity);


        $sharedConfig = new ModuleSharedConfig();

        $pusher = new Pusher(
            $sharedConfig->pusher['authKey'],
            $sharedConfig->pusher['secret'],
            $sharedConfig->pusher['appId'],
            ['cluster' => $sharedConfig->pusher['cluster'],
                'useTLS' => $sharedConfig->pusher['useTLS']]
        );
        $data['type'] = NotificationType::NewUser;
        $data['message'] = 'new user register';
        $data['counter'] = 1;
        $data['date'] = date('Y-m-d H:i:s', time());;
        $pusher->trigger('notification-channel', 'my-event', $data);


        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Auth.registerSuccess'))
            ->setContentType('application/json');


    }

//--------------------------------------------------------------------
// Forgot Password
//--------------------------------------------------------------------

    /**
     * Displays the forgot password form.
     */
    public
    function forgot(): ResponseInterface
    {


        $rules = [

            'login' => 'required',
            'action' => 'required',
            'token' => 'required',

        ];

        if (!$this->validate($rules)) {


            return $this->response->setJSON(['error' => service('validation')->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');

        }

        $authConfig = new  \Modules\Auth\Config\ModuleAuthConfig();
        // ->setExpectedHostname($_SERVER['SERVER_NAME'])
        $recaptcha = new ReCaptcha($authConfig->captcha['secretKey']);

        $resp = $recaptcha->setExpectedAction($this->request->getVar('action'))
            ->setScoreThreshold(0.2)
            ->verify($this->request->getVar('token'), $_SERVER['REMOTE_ADDR']);
        // verify the response
        if (!$resp->isSuccess()) {
            // spam submission
            // show error message
            return $this->response->setJSON([
                'error' => $resp->getErrorCodes()])
                ->setStatusCode(ResponseInterface:: HTTP_UNAUTHORIZED, lang('Authenticate.auth.captchaError'))
                ->setContentType('application/json');
        }


        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->logInMode(false)->generateResetHash();
        unset($authEntity->token);
        unset($authEntity->action);
        $authService = Services::authService();
        $authService->forgot($authEntity);


        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.forgotEmailSmsSent'))
            ->setContentType('application/json');

    }

    /**
     * Displays the Reset Password form.
     */
    /**
     * Verifies the code with the email and saves the new password,
     * if they all pass validation.
     *
     * @return mixed
     */

    public
    function resetPasswordViaSms(): ResponseInterface
    {


        $rules = [
            'code' => 'required',
            'phone' => 'required',
            'password' => 'required',
            'passConfirm' => 'required|matches[password]',
        ];

        if (!$this->validate($rules)) {

            return $this->response->setJSON(['error' => $this->validator->getErrors(),])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');

        }

        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->resetPassword();
        $authService = Services::authService();
        $authService->resetPasswordViaSms($authEntity);


        return $this->response->setJSON(['success' => true])->setStatusCode(ResponseInterface::HTTP_OK, lang('Auth.resetSuccess'))
            ->setContentType('application/json');


    }

    /**
     * Verifies the code with the email and saves the new password,
     * if they all pass validation.
     *
     * @return mixed
     */

    public
    function resetPasswordViaEmail(): ResponseInterface
    {


        $rules = [
            'token' => 'required',
            'email' => 'required|valid_email',
            'password' => 'required',
            'passConfirm' => 'required|matches[password]',
        ];


        if (!$this->validate($rules)) {

            return $this->response->setJSON(['error' => $this->validator->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }

        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->resetPassword()
            ->userAgent($this->request->getUserAgent())
            ->ipAddress($this->request->getIPAddress());
        $authService = Services::authService();
        $authService->resetPasswordViaEmail($authEntity);

        return $this->response->setJSON(['success' => true])->setStatusCode(ResponseInterface::HTTP_OK, lang('Auth.resetSuccess'))
            ->setContentType('application/json');


    }

    /**
     * Activate account.
     *
     * @return mixed
     */
    public
    function activateAccountViaEmail(): ResponseInterface
    {
        $rules = [
            'token' => 'required',
            'email' => 'required|valid_email',
        ];
        if (!$this->validate($rules)) {

            return $this->response->setJSON([

                'error' => $this->validator->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }


        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->activate()
            ->userAgent($this->request->getUserAgent())
            ->ipAddress($this->request->getIPAddress());


        $authService = Services::authService();
        $authService->activateAccountViaEmail($authEntity);

        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Auth.registerSuccess'))
            ->setContentType('application/json');


    }

    /**
     * Resend activation account.
     *
     * @return mixed
     * @throws \Exception
     */
    public
    function sendActivateCodeViaEmail(): ResponseInterface
    {


        $rules = [
            'email' => 'required',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON(['error' => service('validation')->getErrors()
            ])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }


        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->generateActivateHash();
        $authService = Services::authService();
        $authService->sendActivateCodeViaEmail($authEntity);

        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Auth.activationSuccess'))
            ->setContentType('application/json');

    }

    /**
     * Activate account via sma.
     *
     * @return mixed
     */
    public
    function activateAccountViaSms(): ResponseInterface
    {

        $rules = [
            'phone' => 'required',
            'code' => 'required',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON(['error' => service('validation')->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }


        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authEntity->activate();
        $authService = Services::authService();
        $authService->activateAccountViaSms($authEntity);


        return $this->response->setJSON(['success' => true])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.registerSuccess'))
            ->setContentType('application/json');

    }

    /**
     * Activate account via sma.
     *
     * @return mixed
     */
    public
    function sendActivateCodeViaSms(): ResponseInterface
    {

        $rules = [
            'phone' => 'required',
        ];

        if (!$this->validate($rules)) {
            return $this->response->setJSON(['error' => service('validation')->getErrors()])
                ->setStatusCode(ResponseInterface::HTTP_NOT_ACCEPTABLE, lang('Authenticate.auth.validation'))
                ->setContentType('application/json');
        }

        $authEntity = new AuthEntity((array)$this->request->getVar());
        $authService = Services::authService();
        $authService->sendActivateCodeViaSms($authEntity);


        return $this->response->setJSON(['success' => true,
        ])
            ->setStatusCode(ResponseInterface::HTTP_OK, lang('Authenticate.auth.smsActivation'))
            ->setContentType('application/json');


    }


}

entity auth

<?php namespace Modules\Auth\Entities;

use \CodeIgniter\Entity;
use CodeIgniter\I18n\Time;
use Myth\Auth\Authorization\GroupModel;
use Myth\Auth\Authorization\PermissionModel;
use Myth\Auth\Entities\User;
use Myth\Auth\Password;

class  AuthEntity extends Entity
{

    protected $id;
    protected $phone;
    protected $username;
    protected $image;
    protected $email;
    protected $password;
    protected $login;
    protected $loginType;
    protected $remember;
    protected $IpAddress;
    protected $userAgent;
    protected $role;
    protected $code;
    protected $token;
    protected $action;


    protected $attributes = [
        'id' => null,
        'username' => null,
        'phone' => null,
        'email' => null,
        'active' => null,
        'created_at' => null,
        'login' => null,
        'loginType' => null,
        'password' => null,
        'ip_address' => null,
        'date' => null,
        'success' => null,
        'role' => null,
        'code' => null,
        'token' => null,
        'user_agent' => null,
        'remember' => null,

    ];
    protected $datamap = [

        'createdAt' => 'created_at',
        'ipAddress' => 'ip_address',
        'userAgent' => 'user_agent',

    ];


    /**
     * Define properties that are automatically converted to Time instances.
     */
    protected $dates = ['reset_at', 'reset_expires', 'created_at', 'updated_at', 'deleted_at'];

    /**
     * Array of field names and the type of value to cast them as
     * when they are accessed.
     */
    protected $casts = [
        'active' => 'boolean',
        'force_pass_reset' => 'boolean',
    ];

    /**
     * Per-user permissions cache
     * @var array
     */
    protected $permissions = [];

    /**
     * Per-user roles cache
     * @var array
     */
    protected $roles = [];

    /**
     * Automatically hashes the password when set.
     *
     * @see https://paragonie.com/blog/2015/04/secure-authentication-php-with-long-term-persistence
     *
     * @param string $password
     */
    public function setPassword(string $password)
    {
        $this->attributes['password'] = $password;
        $this->attributes['password_hash'] = Password::hash($password);

        /*
            Set these vars to null in case a reset password was asked.
            Scenario:
                user (a *dumb* one with short memory) requests a
                reset-token and then does nothing => asks the
                administrator to reset his password.
            User would have a new password but still anyone with the
            reset-token would be able to change the password.
        */
        $this->attributes['reset_hash'] = null;
        $this->attributes['reset_at'] = null;
        $this->attributes['reset_expires'] = null;
    }

    /**
     * Force a user to reset their password on next page refresh
     * or login. Checked in the LocalAuthenticator's check() method.
     *
     * @return $this
     * @throws \Exception
     *
     */
    public function forcePasswordReset(): AuthEntity
    {
        $this->generateResetHash();
        $this->attributes['force_pass_reset'] = 1;

        return $this;
    }

    /**
     * Generates a secure hash to use for password reset purposes,
     * saves it to the instance.
     *
     * @return $this
     * @throws \Exception
     */
    public function generateResetHash(): AuthEntity
    {
        $this->attributes['reset_hash'] = bin2hex(random_bytes(16));
        $this->attributes['reset_expires'] = date('Y-m-d H:i:s', time() + config('Auth')->resetTime);

        return $this;
    }

    /**
     * Generates a secure random hash to use for account activation.
     *
     * @return $this
     * @throws \Exception
     */
    public function generateActivateHash(): AuthEntity
    {
        $this->attributes['activate_hash'] = bin2hex(random_bytes(16));

        return $this;
    }

    /**
     * Activate user.
     *
     * @return $this
     */
    public function activate(): AuthEntity
    {
        $this->attributes['active'] = 1;
        $this->attributes['activate_hash'] = null;

        return $this;
    }

    /**
     * Unactivate user.
     *
     * @return $this
     */
    public function deactivate(): AuthEntity
    {
        $this->attributes['active'] = 0;

        return $this;
    }

    /**
     * Checks to see if a user is active.
     *
     * @return bool
     */
    public function isActivated(): bool
    {
        return isset($this->attributes['active']) && $this->attributes['active'] == true;
    }


    public function logInMode($flag = true): AuthEntity
    {
// Determine credential type

        if ($flag == false) {

            if (filter_var($this->attributes['login'], FILTER_VALIDATE_EMAIL)) {
                $this->attributes['loginType'] = 'email';

            } else if (is_numeric($this->attributes['login'])) {
                $this->attributes['loginType'] = 'phone';

            } else {
                $this->attributes['loginType'] = 'username';

            }

        } else {


            if (filter_var($this->attributes['login'], FILTER_VALIDATE_EMAIL)) {
                $this->attributes['loginType'] = 'email';
                $this->attributes['email'] = $this->attributes['login'];
            } else if (is_numeric($this->attributes['login'])) {
                $this->attributes['loginType'] = 'phone';
                $this->attributes['phone'] = $this->attributes['login'];

            } else {
                $this->attributes['loginType'] = 'username';
                $this->attributes['username'] = $this->attributes['login'];
            }
        }
        return $this;
    }

    public function ipAddress(string $ip): AuthEntity
    {
        $this->attributes['ip_address'] = $ip;
        return $this;
    }

    public function loginDate(): AuthEntity
    {
        $this->attributes['date'] = date('Y-m-d H:i:s', time());;
        return $this;
    }

    public function loginSuccess(bool $flag): AuthEntity
    {
        $this->attributes['success'] = $flag;
        return $this;
    }

    public function createdAt(): AuthEntity
    {
        $this->attributes['created_at'] = date('Y-m-d H:i:s', time());;
        return $this;
    }

    public function setRole(string $role): AuthEntity
    {
        $this->attributes['role'] = $role;
        return $this;
    }

    public function resetPassword(): AuthEntity
    {
        $this->attributes['reset_hash'] = null;
        $this->attributes['reset_expires'] = null;
        $this->attributes['reset_at'] = date('Y-m-d H:i:s');
        $this->attributes['force_pass_reset'] = false;


        return $this;
    }

    public function userAgent(string $agent): AuthEntity
    {
        $this->attributes['user_agent'] = $agent;
        return $this;
    }
}


0
paliz On

service auth

<?php namespace Modules\Auth\Services;


use Codeigniter\Config\Services;
use CodeIgniter\Session\SessionInterface;
use Config\Email;
use Modules\Auth\Config\ModuleAuthConfig;
use Modules\Auth\Entities\AuthEntity;
use Modules\Auth\Interfaces\AuthServiceInterface;
use Modules\Auth\Models\GroupsPermissionModel;
use Modules\Auth\Models\UsersPermissionModel;
use Modules\Shared\Config\ModuleSharedConfig;
use Modules\Shared\Libraries\MainService;
use Modules\Shared\Libraries\Sms;
use CodeIgniter\HTTP\ResponseInterface;
use Modules\Auth\Libraries\CsrfSecurity;
use Myth\Auth\Authorization\GroupModel;
use Myth\Auth\Authorization\PermissionModel;
use Myth\Auth\AuthTrait;


use Myth\Auth\Models\LoginModel;
use Myth\Auth\Models\UserModel;
use Myth\Auth\Password;


class AuthService extends MainService implements AuthServiceInterface
{
    use AuthTrait;

    private CsrfSecurity $csrfSecurity;
    private GroupModel $groupModel;
    private PermissionModel $permissionModel;
    private ModuleAuthConfig $authConfig;
    private UserModel $userModel;
    private SessionInterface $session;
    private LoginModel $loginModel;
    private ModuleSharedConfig $sharedConfig;
    private Sms $sms;
    private GroupsPermissionModel $groupsPermissionModel;
    private UsersPermissionModel $usersPermissionModel;

    private \CodeIgniter\Email\Email $email;


    public function __construct()
    {
        $this->userModel = new UserModel();
        $this->authConfig = new  ModuleAuthConfig();
        $this->groupModel = new GroupModel();
        $this->csrfSecurity = new CsrfSecurity();
        $this->permissionModel = new PermissionModel();
        $this->loginModel = new LoginModel();
        $this->session = \Config\Services::session();
        $this->sharedConfig = new ModuleSharedConfig();
        $this->sms = new Sms($this->sharedConfig->sms['userName'],
            $this->sharedConfig->sms['password'],
            0);
        $this->groupsPermissionModel = new GroupsPermissionModel();
        $this->usersPermissionModel = new UsersPermissionModel();

        $this->email = Services::email();
        $emailConfig = new Email();
        $this->email->initialize($emailConfig)->
        setFrom($emailConfig->fromEmail, getenv('siteAddress'));
    }

    public function signInJwt(AuthEntity $entity): array
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_CONFLICT);


        $findUser = $this->userModel->asObject()->where($entity->loginType, $entity->login)->first();

        if (!$findUser) {
            $entity->loginSuccess(false);
            $this->loginModel->save($entity);
            $this->httpException(lang('Authenticate.auth.accountNotExist'), ResponseInterface::HTTP_CONFLICT);
        }
        if ($findUser->active == false) {
            $entity->loginSuccess(false);
            $this->loginModel->save($entity);
            $this->httpException(lang('Authenticate.auth.accountNotActive'), ResponseInterface::HTTP_CONFLICT);

        }
        if ($findUser->status == true) {
            $entity->loginSuccess(false);
            $this->loginModel->save($entity);
            $this->httpException(lang('Authenticate.auth.accountIsBand'), ResponseInterface::HTTP_CONFLICT);

        }

        if (!Password::verify($entity->password, $findUser->password_hash)) {
            $entity->loginSuccess(false);
            $this->loginModel->save($entity);
            $this->httpException(lang('Authenticate.auth.accountNotExist'), ResponseInterface::HTTP_CONFLICT);

        }

        $entity->loginSuccess(true);
       $this->loginModel->save($entity);

        $role = $this->groupModel->asObject()->getGroupsForUser($findUser->id);

        $permissions = $this->permissionModel->asObject()->where('active', '1')->findAll();
        $permissionUser = $this->usersPermissionModel->permissionsOfUser($findUser->id);
        $permissionGroup = $this->groupsPermissionModel->permissionsOfGroup($role[0]['group_id']);

        helper('jwt');

        $timeJwt = isset($entity->remember) ? timeJwt(true) : timeJwt(false);

        $jwtToken = generateJWT($findUser->id, $timeJwt['init'], $timeJwt['expire'], $this->authConfig->jwt['secretKey']);

        $data = [
            'success' => true,
            'role' => [
                'name' => $role[0]['name'],
                'id' => $role[0]['group_id']
            ],
            'permissions' => $permissions,
            'permissionUser' => $permissionUser,
            'permissionGroup' => $permissionGroup,
            'userInformation' => [
                'id' => $findUser->id,
                'userName' => $findUser->username,
                'image' => $findUser->image,
                'firstName' => $findUser->first_name,
                'lastName' => $findUser->last_name,
                'email' => $findUser->email,
                'phone' => $findUser->phone,
            ],
            'csrf' => $this->csrfSecurity->init(),
            'jwt' => [
                "token" => $jwtToken,
                "expire" => $timeJwt['expire'],
            ],

        ];

        return $data;


    }

    public function signIn(AuthEntity $entity): array
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_CONFLICT);

        helper('cookie');


//
        $findUser = $this->userModel->asObject()->where($entity->loginType, $entity->login)->first();

        $role = $this->groupModel->asObject()->getGroupsForUser($findUser->id);
        $permissions = $this->permissionModel->asObject()->where('active', '1')->findAll();
        $permissionUser = $this->usersPermissionModel->permissionsOfUser($findUser->id);
        $permissionGroup = $this->groupsPermissionModel->permissionsOfGroup($findUser->id);

        // store user inof in session
//        $this->session->set('userInformation', [
//            'userName' => $this->authenticate->user()->username,
//            'image' => $this->authenticate->user()->image,
//            'firstName' => $this->authenticate->user()->first_name,
//            'lastName' => $this->authenticate->user()->last_name,
//            'email' => $this->authenticate->user()->email,
//            'phone' => $this->authenticate->user()->phone,
//        ]);


        $data = [
            'success' => true,
            'role' => [
                'name' => $role[0]['name'],
                'id' => $role[0]['group_id']
            ],
            'permissions' => $permissions,
            'permissionUser' => $permissionUser,
            'permissionGroup' => $permissionGroup,
            'userInformation' => [
                'id' => $findUser->id,
                'userName' => $findUser->username,
                'image' => $findUser->image,
                'firstName' => $findUser->first_name,
                'lastName' => $findUser->last_name,
                'email' => $findUser->email,
                'phone' => $findUser->phone,
            ],
            'csrf' => $this->csrfSecurity->init(),
        ];

        return $data;

    }


    /**
     * Log the user out.
     * @param object $userData
     */
    public function signOutJwt(object $userData): void
    {
        if (!isset($userData->id)) $this->httpException(lang('Authenticate.filter.jwt'), ResponseInterface::HTTP_CONFLICT);


        $findUser = $this->userModel->asObject()->where("id", $userData->id)->first();

        if (is_null($findUser)) $this->httpException(lang('Auth.forgotNoUser'), ResponseInterface::HTTP_UNAUTHORIZED);


    }



    //--------------------------------------------------------------------
    // Register
    //--------------------------------------------------------------------

    /**
     * Displays the user registration page.
     * @param AuthEntity $entity
     */
    public function signUp(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_CONFLICT);

        $entity->generateActivateHash();

        $this->userModel->withGroup($entity->role);

        if (!$this->userModel->save($entity)) {


            $message = lang('Authenticate.auth.rejectRegistration') . " , " . serializeMessages($this->userModel->errors());
            $this->httpException($message, ResponseInterface::HTTP_BAD_REQUEST);

        }


        if ($entity->loginType == 'email') {


            $isSent = $this->email
                ->setTo($entity->email)
                ->setSubject(lang('Auth.activationSubject'))
                ->setMessage(view($this->authConfig->views['emailActivation'],
                    ['hash' => $entity->toArray()['activate_hash']]))
                ->setMailType('html')->send();


            if (!$isSent) {
                $this->groupModel->removeUserFromAllGroups($this->userModel->getInsertID());
                $this->userModel->where('id', $this->userModel->getInsertID())->delete();


                $message = lang('Authenticate.auth.failRegistration') . " , " . serializeMessages($this->activator->error() ?? lang('Auth.unknownError'));
                $this->httpException($message,
                    ResponseInterface::HTTP_BAD_REQUEST, $this->email->printDebugger(['headers']));

            }
        } else if ($entity->loginType == 'phone') {


            $isSend = $this->sms->sendActivationCode($entity->phone, getenv('siteAddress'));

            if ($isSend < 2000) {

                $message = lang('Authenticate.auth.smsSendFail');
                $this->httpException($message, ResponseInterface::HTTP_FOUND);

            }
        }


    }

//--------------------------------------------------------------------
// Forgot Password
//--------------------------------------------------------------------

    /**
     * Displays the forgot password form.
     * @param AuthEntity $entity
     */
    public
    function forgot(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_CONFLICT);


        $findUser = $this->userModel->where($entity->loginType, $entity->login)->first();

        if (is_null($findUser)) $this->httpException(lang('Auth.forgotNoUser'), ResponseInterface::HTTP_UNAUTHORIZED);

        $statusEmail = false;
        $statusSms = 0;
        if (!is_null($findUser->email)) {

            $statusEmail = $this->email
                ->setTo($findUser->email)
                ->setSubject(lang('Auth.forgotSubject'))
                ->setMessage(view($this->authConfig->views['emailForgot'],
                    ['hash' => $entity->toArray()['reset_hash']]))
                ->setMailType('html')->send();


        }


        if (!is_null($findUser->phone)) {

            $statusSms = $this->sms->sendActivationCode($findUser->phone, getenv('siteAddress'));

        }


        if ($statusSms < 2000 && !$statusEmail) $this->httpException(lang('Auth.unknownError'),
            ResponseInterface::HTTP_BAD_REQUEST, $this->email->printDebugger(['headers']));


        if (!$this->userModel->update($findUser->id, $entity)) {


            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }


    }


    /**
     * Verifies the code with the email and saves the new password,
     * if they all pass validation.
     *
     * @param AuthEntity $entity
     */

    public
    function resetPasswordViaSms(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);


        $findUser = $this->userModel->where('phone', $entity->phone)->first();;


        if (is_null($findUser)) $this->httpException(lang('Authenticate.forgotNoUserPhone'), ResponseInterface::HTTP_CONFLICT);


        if (!$this->sms->isActivationCodeValid($entity->phone, $entity->code)) $this->httpException(lang('Auth.resetTokenExpired'), ResponseInterface::HTTP_NOT_ACCEPTABLE);


        unset($entity->phone);
        if (!$this->userModel->update($findUser->id, $entity)) {


            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }


    }

    /**
     * Verifies the code with the email and saves the new password,
     * if they all pass validation.
     *
     * @param AuthEntity $entity
     */

    public
    function resetPasswordViaEmail(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);


        $this->userModel->logResetAttempt(
            $entity->email,
            $entity->token,
            $entity->ip_address,
            $entity->user_agent
        );


        $findUser = $this->userModel->where('email', $entity->email)
            ->where('reset_hash', $entity->token)->first();


        if (is_null($findUser)) $this->httpException(lang('Auth.forgotNoUser'), ResponseInterface::HTTP_CONFLICT);


        // Reset token still valid?
        if (!empty($findUser->reset_expires) && time() > $findUser->reset_expires->getTimestamp()) $this->httpException(lang('Auth.resetTokenExpired'), ResponseInterface::HTTP_NOT_ACCEPTABLE);

        unset($entity->email);
        if (!$this->userModel->update($findUser->id, $entity)) {

            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }

    }

    /**
     * Activate account.
     *
     * @param AuthEntity $entity
     */
    public
    function activateAccountViaEmail(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);

        $this->userModel->logActivationAttempt(
            $entity->token,
            $entity->ip_address,
            $entity->user_agent
        );


        $findUser = $this->userModel->where('activate_hash', $entity->token)
            ->where('active', 0)->where('email', $entity->email)
            ->first();
        if (is_null($findUser)) $this->httpException(lang('Auth.activationNoUser'), ResponseInterface::HTTP_CONFLICT);

        unset($entity->email);
        if (!$this->userModel->update($findUser->id, $entity)) {

            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }

    }

    /**
     * Resend activation account.
     * @param AuthEntity $entity
     */
    public
    function sendActivateCodeViaEmail(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);

        $findUser = $this->userModel->where('email', $entity->email)
            ->where('active', 0)
            ->first();

        if (is_null($findUser)) $this->httpException(lang('Auth.activationNoUser'), ResponseInterface::HTTP_CONFLICT);


        $isSent = $this->email
            ->setTo($entity->email)
            ->setSubject(lang('Auth.activationSubject'))
            ->setMessage(view($this->authConfig->views['emailActivation'],
                ['hash' => $entity->toArray()['activate_hash']]))
            ->setMailType('html')->send();

        if (!$isSent) {


            $this->httpException(lang('Auth.unknownError'),
                ResponseInterface::HTTP_BAD_REQUEST, $this->email->printDebugger(['headers']['headers'] ?? lang('Auth.unknownError')));

        }
        unset($entity->email);


        if (!$this->userModel->update($findUser->id, $entity)) {


            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }

    }

    /**
     * Activate account via sma.
     *
     * @param AuthEntity $entity
     */
    public function activateAccountViaSms(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);

        $result = $this->sms->isActivationCodeValid($entity->phone,
            $entity->code);

        if ($result == false) $this->httpException(lang('Authenticate.auth.smsActivationFail'), ResponseInterface::HTTP_CONFLICT);

        $findUser = $this->userModel->where('active', 0)
            ->where('phone', $entity->phone)->first();

        if (is_null($findUser)) $this->httpException(lang('Auth.activationNoUser'), ResponseInterface::HTTP_CONFLICT);

        unset($entity->phone);
        if (!$this->userModel->update($findUser->id, $entity)) {

            $this->httpException(lang('Shared.api.reject'), ResponseInterface::HTTP_BAD_REQUEST, serializeMessages($this->userModel->errors()));

        }
    }

    /**
     * Activate account via sma.
     *
     * @param AuthEntity $entity
     */
    public
    function sendActivateCodeViaSms(AuthEntity $entity): void
    {
        if (is_null($entity)) $this->httpException(lang('Shared.api.validation'), ResponseInterface::HTTP_NOT_ACCEPTABLE);

        $findUser = $this->userModel
            ->where('active', 0)->where('phone', $entity->phone)->first();
        if (is_null($findUser)) $this->httpException(lang('Auth.activationNoUser'), ResponseInterface::HTTP_CONFLICT);

        $result = $this->sms->sendActivationCode($entity->phone, getenv('siteAddress'));
        if ($result < 2000) $this->httpException(lang('Authenticate.auth.smsSendFail'), ResponseInterface::HTTP_BAD_REQUEST);


    }


}