protected function validate(\ICanboogie\Errors $errors) { global $core; $request = $this->request; $username = $request[User::USERNAME]; $password = $request[User::PASSWORD]; $uid = $core->models['users']->select('uid')->where('username = ? OR email = ?', $username, $username)->rc; if (!$uid) { $errors[User::PASSWORD] = new FormattedString('Unknown username/password combination.'); return false; } $user = $core->models['users'][$uid]; $now = time(); $login_unlock_time = $user->metas['login_unlock_time']; if ($login_unlock_time) { if ($login_unlock_time > $now) { throw new \ICanBoogie\HTTP\HTTPError(\ICanBoogie\format("The user account has been locked after multiple failed login attempts.\n\t\t\t\t\tAn e-mail has been sent to unlock the account. Login attempts are locked until %time,\n\t\t\t\t\tunless you unlock the account using the email sent.", ['%count' => $user->metas['failed_login_count'], '%time' => I18n\format_date($login_unlock_time, 'HH:mm')]), 403); } $user->metas['login_unlock_time'] = null; } if (!$user->verify_password($password)) { $errors[User::PASSWORD] = new FormattedString('Unknown username/password combination.'); $user->metas['failed_login_count'] += 1; $user->metas['failed_login_time'] = $now; if ($user->metas['failed_login_count'] >= 10) { $token = \ICanBoogie\generate_token(40, \ICanBoogie\TOKEN_ALPHA . \ICanBoogie\TOKEN_NUMERIC); $user->metas['login_unlock_token'] = $token; $user->metas['login_unlock_time'] = $now + 3600; $until = I18n\format_date($now + 3600, 'HH:mm'); $url = $core->site->url . '/api/users/unlock_login?' . http_build_query(['username' => $username, 'token' => $token, 'continue' => $request->uri]); $t = new Proxi(['scope' => [\ICanBoogie\normalize($user->constructor, '_'), 'connect', 'operation']]); $core->mail(['destination' => $user->email, 'from' => 'no-reply@' . $_SERVER['HTTP_HOST'], 'subject' => "Your account has been locked", 'body' => <<<EOT You receive this message because your account has been locked. After multiple failed login attempts your account has been locked until {$until}. You can use the following link to unlock your account and try to login again: <{$url}> If you forgot your password, you'll be able to request a new one. If you didn't try to login neither forgot your password, this message might be the result of an attack attempt on the website. If you think this is the case, please contact its admin. The remote address of the request was: {$request->ip}. EOT ]); unset($errors[User::PASSWORD]); $errors[] = new FormattedString("Your account has been locked, a message has been sent to your e-mail address."); } return false; } if (!$user->is_admin && !$user->is_activated) { $errors[] = new FormattedString('User %username is not activated', ['%username' => $username]); return false; } $this->record = $user; return true; }
protected static function generate_token() { $possible = \ICanboogie\TOKEN_ALPHA; for (;;) { $token = \ICanBoogie\generate_token(6, $possible); if (empty($tokens[$token])) { return $tokens[$token] = $token; } } }
public function __construct() { global $core; $values = array(); if (isset($core->session->install['user'])) { $values = $core->session->install['user']; if (isset($values['password'])) { $values['password']; $values['password_confirm'] = $values['password']; } } $random_password = \ICanBoogie\generate_token(8, \ICanBoogie\TOKEN_MEDIUM); parent::__construct(array(PanelDecorator::TITLE => t('panel.user.title'), PanelDecorator::DESCRIPTION => t('panel.user.description'), Form::VALUES => $values, Form::HIDDENS => array('random_password' => $random_password), Element::CHILDREN => array('username' => new Text(array(Group::LABEL => 'Username', Element::DESCRIPTION => t('panel.user.username'), Element::DEFAULT_VALUE => 'admin')), 'email' => new Text(array(Group::LABEL => 'Your E-mail', Element::REQUIRED => true, Element::DESCRIPTION => t('panel.user.email'))), 'password' => new Text(array(Group::LABEL => 'Password', Element::DESCRIPTION => t('panel.user.password'), 'type' => 'password', 'placeholder' => $random_password)), 'password_confirm' => new Text(array(Element::DESCRIPTION => t('panel.user.password_confirm'), Element::LABEL_MISSING => "Password confirm", 'type' => 'password', 'placeholder' => empty($values['password']) ? $random_password : null)), 'language' => new LanguageElement(array(Group::LABEL => 'Language', Element::DESCRIPTION => t('panel.user.language')))), 'action' => '/api/install/user', 'autocomplete' => 'off', 'name' => 'user')); }
/** * Generates a unique 40 characters long token. * * @return string */ public function generate_token() { for (;;) { if (function_exists('openssl_random_pseudo_bytes')) { $token = sha1(openssl_random_pseudo_bytes(256)); } else { $token = \ICanBoogie\generate_token(40, \ICanBoogie\TOKEN_ALPHA . \ICanBoogie\TOKEN_NUMERIC); } if ($this->filter_by_token($token)->one) { continue; } return $token; } }