Login * @copyright Tamaranga */ class Login extends AuthForm { /** @var string */ public $title = ''; /** @var string */ public $back = ''; public function init() { parent::init(); $this->setTemplate('auth/login', 'users'); } public function data() { $data = parent::data(); if ($this->request->user()) { return Users::redirectToAccountSettings(); } $data['title'] = _t('users', 'Sign In'); if (empty($this->back)) { $data['back'] = $this->request->get('ref', TYPE_STR); } $data['emailOnly'] = $this->emailOnly(); $data['forgot_url'] = $this->forgotUrl(); $data['register_url'] = $this->registrationUrl('start'); $data['providers'] = Users::social()->getProvidersEnabled(); $data['login_social_url'] = Users::url('login.social'); return $data; } public function validate($data = []) { $data = $this->validateUsingRules($data, [ 'email' => [TYPE_NOTAGS, 'len' => 100], /** Phone number may come from "Social" registration form */ 'phone_number' => [TYPE_NOTAGS, 'len' => 30], 'pass' => [TYPE_NOTRIM, 'required' => _t('users', 'Enter password')], 'social' => [TYPE_BOOL], # Using Social Account 'remember' => [TYPE_BOOL], # Remember Me 'back' => [TYPE_NOTAGS], # Return Url ]); do { if ($this->emailOnly() && ! $this->input->isEmail($this->email)) { $this->errors->set(_t('users', 'Incorrect email'), 'email'); break; } } while (false); # Blocks if ($this->errors->no()) { $data = $this->validateBlocks($data); } return $data; } public function submit() { # Resending the "activation" letter if ($this->request->get('step', TYPE_STR) === 'resend-activation') { do { if (! $this->security->validateReferer()) { $this->errors->reloadPage(); break; } if ($this->tooManyRequests('users-login-resend-activation', ['timeout' => 5, 'silent' => true])) { $this->errors->set(_t('', 'Please, try again in a couple of seconds')); break; } if ($this->request->user()) { $this->errors->reloadPage(); break; } $email = $this->request->post('email', [TYPE_NOTAGS, 'len' => 100]); $pass = $this->request->post('pass', TYPE_NOTRIM); # Open password $response = $this->resendActivation($email, $pass); if (is_array($response)) { $this->respond($response); } } while (false); return parent::submit(); } $this->respond([ 'success' => false, 'status' => 0, ]); do { # Already authenticated if ($this->request->user()) { $this->respond('success', true); break; } # Validate $this->validate(); if ($this->errors->any()) { break; } # Is IP in blacklist if ($blockedReason = Users::checkBan($this->request->remoteAddress())) { $this->errors->set(_t('users', 'Access denied due to: [reason]', [ 'reason' => $blockedReason, ])); break; } if ($this->tooManyRequests('users-login', ['timeout' => rand(3, 6), 'silent' => true])) { $this->errors->set(_t('', 'Please, try again in a couple of seconds')); break; } # Authenticate by: email or phone_number $credentials = []; if ($this->input->isEmail($this->email)) { $credentials = ['email' => $this->email]; } elseif ($this->input->isPhoneNumber($this->email)) { $credentials = ['phone_number' => $this->email]; } elseif ($this->input->isPhoneNumber($this->phone_number)) { $credentials = ['phone_number' => $this->phone_number]; } $result = Users::authByCredentials($credentials, $this->pass, [ 'remember' => $this->remember, 'silent' => false, ]); # Correct password: confirm phone number & activate account if ( $result === 1 && /* not active */ array_key_exists('phone_number', $credentials) && $this->phoneOnly() ) { $userData = $this->config('__users_preactivate_data'); Users::userActivate($userData['id'], ['verifyPhone' => true]); # Try again $result = Users::authByCredentials($credentials, $this->pass, [ 'remember' => $this->remember, 'silent' => false, ]); } # Account needs activation if ($result === 1) { $this->respond('status', 1); $userData = $this->config('__users_preactivate_data'); $userData = Users::model()->userData($userData['id'], [ 'user_id as id', 'email', 'name', 'activate_key', 'phone_number', 'phone_number_verified', 'email_verified', 'password', ]); # Phone activation: if ( ($this->phoneOnly() || $this->phoneAndEmail()) && ! empty($userData['phone_number']) && empty($userData['phone_number_verified']) ) { if (empty($userData['activate_key'])) { # Update activation key $activationData = Users::updateActivationKey($userData['id']); if (! $activationData) { $this->errors->set(_t('users', 'Registration error, contact the administrator')); break; } else { $userData['activate_key'] = $activationData['key']; } } # Send activation code to confirm phone number Users::sms(false)->sendActivationCode($userData['phone_number'], $userData['activate_key']); $this->startData([ 'id' => $userData['id'], 'password' => $this->pass, ]); $this->errors->set(_t('users', 'This account is not activated. Activate', [ 'link_activate' => 'href="' . $this->registrationUrl('phone') . '"' ])); } # Email activation: if ($this->emailOnly() && ! empty($userData['email']) && empty($userData['email_verified'])) { $this->errors->set(_t('users', 'This account is not activated, please follow the link sent to your email.
Retrieve email', [ 'link_resend' => 'href="javascript:void(0);" class="ajax j-resend-activation"', ])); } break; } # Success if ($result === true) { $userID = $this->request->user()->id(); # Link social account if ($this->social) { Users::social()->authFinish($userID); } # Save favorite listings Listings::favorites()->onUserLogin($userID); # todo: listen @see \modules\users\events\Login $this->respond([ 'success' => true, 'status' => 2, # success ]); break; } } while (false); if ($this->respond('success')) { if ( empty($this->back) || mb_strpos($this->back, '/user/register') !== false || mb_strpos($this->back, '/user/login') !== false || ! $this->security->validateReferer($this->back) ) { $this->back = $this->router->url('index'); } $this->respond('redirect', $this->back); } return parent::submit(); } /** * Resend confirmation email notification with "activation link" * @param string $email * @param string $password * @return array|bool */ public function resendActivation(string $email, string $password) { if (! $this->input->isEmail($email)) { $this->errors->set(_t('users', 'Incorrect email'), 'email'); return false; } $user = Users::model()->userDataByFilter(['email' => $email], [ 'user_id','name','password','password_salt','activate_key', 'phone_number','email_verified', ]); if (empty($user) || $user['email_verified']) { $this->errors->reloadPage(); return false; } # Compare password if (! $this->security->passwordCheck($password, $user['password'], $user['password_salt'])) { $this->errors->set(_t('users', 'Incorrect email or password'), 'email'); return false; } # Regenerate activation data $activation = Users::updateActivationKey($user['user_id'], $user['activate_key']); if (! $activation) { $this->errors->reloadPage(); return false; } # Send confirmation notification Users::sendEmailRegistrationConfirmation($user['user_id'], $email, $password, $activation['link']); # Save data for next step $this->startData([ 'id' => $user['user_id'], 'password' => $password, 'activate_link' => $activation['link'], ]); return [ 'redirect' => $this->registrationUrl('emailed', ['resend' => 1]) ]; } }