* * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ namespace pcrt\User\Form; use pcrt\User\Helper\SecurityHelper; use pcrt\User\Model\User; use pcrt\User\Query\UserQuery; use pcrt\User\Traits\ContainerAwareTrait; use pcrt\User\Traits\ModuleAwareTrait; use pcrt\User\Validator\TwoFactorCodeValidator; use pcrt\User\Validator\TwoFactorEmailValidator; use pcrt\User\Validator\TwoFactorTextMessageValidator; use Yii; use yii\base\InvalidParamException; use yii\base\Model; use yii\helpers\ArrayHelper; use yii\web\IdentityInterface; class LoginForm extends Model { use ModuleAwareTrait; use ContainerAwareTrait; /** * @var string login User's email or username */ public $login; /** * @var string User's password */ public $password; /** * @var string User's two-factor authentication code */ public $twoFactorAuthenticationCode; /** * @var bool whether to remember User's login */ public $rememberMe = false; /** * @var User */ protected $user; /** * @var UserQuery */ protected $query; /** * @var SecurityHelper */ protected $securityHelper; /** * @param UserQuery $query * @param SecurityHelper $securityHelper * @param array $config */ public function __construct(UserQuery $query, SecurityHelper $securityHelper, $config = []) { $this->query = $query; $this->securityHelper = $securityHelper; parent::__construct($config); } /** * {@inheritdoc} */ public function attributeLabels() { return [ 'login' => Yii::t('usuario', 'Login'), 'password' => Yii::t('usuario', 'Password'), 'rememberMe' => Yii::t('usuario', 'Remember me next time'), 'twoFactorAuthenticationCode' => Yii::t('usuario', 'Two factor authentication code') ]; } /** * {@inheritdoc} * * @throws \pcrt\TwoFA\Exception\InvalidSecretKeyException (only if package is being used) */ public function rules() { return [ 'requiredFields' => [['login', 'password'], 'required'], 'requiredFieldsTwoFactor' => [ ['login', 'password', 'twoFactorAuthenticationCode'], 'required', 'on' => '2fa' ], 'loginTrim' => ['login', 'trim'], 'twoFactorAuthenticationCodeTrim' => ['twoFactorAuthenticationCode', 'trim'], 'passwordValidate' => [ 'password', function ($attribute) { if ($this->user === null || !$this->securityHelper->validatePassword($this->password, $this->user->password_hash) ) { $this->addError($attribute, Yii::t('usuario', 'Invalid login or password')); } }, ], 'twoFactorAuthenticationCodeValidate' => [ 'twoFactorAuthenticationCode', function ($attribute) { if ($this->user === null) { $this->addError($attribute, Yii::t('usuario', 'Invalid two factor authentication code')); } else { $module = Yii::$app->getModule('user'); $validators = $module->twoFactorAuthenticationValidators; $type = $this->user->auth_tf_type; $class = ArrayHelper::getValue($validators, $type.'.class'); $codeDurationTime = ArrayHelper::getValue($validators, $type.'.codeDurationTime', 300); $validator = $this ->make($class, [$this->user, $this->twoFactorAuthenticationCode, $this->module->twoFactorAuthenticationCycles]); $success = $validator->validate(); if (!$success) { $this->addError($attribute, $validator->getUnsuccessLoginMessage($codeDurationTime)); } } } ], 'confirmationValidate' => [ 'login', function ($attribute) { if ($this->user !== null) { $module = $this->getModule(); $confirmationRequired = $module->enableEmailConfirmation && !$module->allowUnconfirmedEmailLogin; if ($confirmationRequired && !$this->user->getIsConfirmed()) { $this->addError($attribute, Yii::t('usuario', 'You need to confirm your email address')); } if ($this->user->getIsBlocked()) { $this->addError($attribute, Yii::t('usuario', 'Your account has been blocked')); } } }, ], 'rememberMe' => ['rememberMe', 'boolean'], ]; } /** * Validates form and logs the user in. * * @throws InvalidParamException * @return bool whether the user is logged in successfully */ public function login() { if ($this->validate()) { $duration = $this->rememberMe ? $this->module->rememberLoginLifespan : 0; return Yii::$app->getUser()->login($this->user, $duration); } return false; } /** * {@inheritdoc} */ public function beforeValidate() { if (parent::beforeValidate()) { $this->user = $this->query->whereUsernameOrEmail(trim($this->login))->one(); return true; } return false; } /** * @return User */ public function getUser() { return $this->user; } /** * @param IdentityInterface $user * @return User */ public function setUser(IdentityInterface $user) { return $this->user = $user; } }