Validator

This commit is contained in:
Visman 2017-02-20 21:52:45 +07:00
parent 44bb5dc6ca
commit ffdcefb076
14 changed files with 545 additions and 132 deletions

View file

@ -40,8 +40,8 @@ class Routing
$r->add('GET', '/login/forget', 'Auth:forget', 'Forget');
$r->add('POST', '/login/forget', 'Auth:forgetPost');
// смена пароля
$r->add('GET', '/login/{email}/{key}', 'Auth:changePass', 'ChangePassword');
$r->add('POST', '/login/{email}/{key}', 'Auth:changePassPost');
$r->add('GET', '/login/{email}/{key}/{hash}', 'Auth:changePass', 'ChangePassword');
$r->add('POST', '/login/{email}/{key}/{hash}', 'Auth:changePassPost');
// регистрация
if ($config['o_regs_allow'] == '1') {
@ -120,5 +120,4 @@ class Routing
}
return $page;
}
}

View file

@ -59,7 +59,7 @@ class Router
/**
* Конструктор
* @param string $prefix
* @param string $base
*/
public function __construct($base = '')
{
@ -183,8 +183,6 @@ class Router
return [self::OK, $data[0], $args];
}
}
if (empty($allowed)) {
return [self::NOT_FOUND];
} else {

View file

@ -16,9 +16,7 @@ class Secury
/**
* Конструктор
*
* @param array $hmac
*
* @throws \InvalidArgumentException
* @throws \UnexpectedValueException
*/
@ -35,12 +33,20 @@ class Secury
/**
* Обертка для hash_hmac
*
* @param string $data
* @return string
*/
public function hash($data)
{
return $this->hmac($data, md5(__DIR__));
}
/**
* Обертка для hash_hmac
* @param string $data
* @param string $key
*
* @throws \InvalidArgumentException
* @return string
* @throws \InvalidArgumentException
*/
public function hmac($data, $key)
{
@ -52,11 +58,9 @@ class Secury
/**
* Возвращает случайный набор байтов заданной длины
*
* @param int $len
*
* @throws \RuntimeException
* @return string
* @throws \RuntimeException
*/
public function randomKey($len)
{
@ -76,15 +80,12 @@ class Secury
if (strlen($key) < $len) {
throw new RuntimeException('Could not gather sufficient random data');
}
return $key;
}
/**
* Возвращает случайную строку заданной длины состоящую из символов 0-9 и a-f
*
* @param int $len
*
* @return string
*/
public function randomHash($len)
@ -95,9 +96,7 @@ class Secury
/**
* Возвращает случайную строку заданной длины состоящую из цифр, латиницы,
* знака минус и символа подчеркивания
*
* @param int $len
*
* @return string
*/
public function randomPass($len)
@ -108,15 +107,12 @@ class Secury
for ($i = 0; $i < $len; ++$i) {
$result .= substr($chars, (ord($key[$i]) % strlen($chars)), 1);
}
return $result;
}
/**
* Replacing invalid UTF-8 characters and remove control characters
*
* @param string|array $data
*
* @return string|array
*/
public function replInvalidChars($data)
@ -124,13 +120,11 @@ class Secury
if (is_array($data)) {
return array_map([$this, 'replInvalidChars'], $data);
}
// Replacing invalid UTF-8 characters
// slow, small memory
//$data = mb_convert_encoding((string) $data, 'UTF-8', 'UTF-8');
// fast, large memory
$data = htmlspecialchars_decode(htmlspecialchars((string) $data, ENT_SUBSTITUTE, 'UTF-8'));
// Remove control characters
return preg_replace('%[\x00-\x08\x0B-\x0C\x0E-\x1F]%', '', $data);
}

View file

@ -19,7 +19,6 @@ class Csrf
/**
* Конструктор
*
* @param Secury $secury
* @param User $user
*/
@ -51,7 +50,7 @@ class Csrf
* @param array $args
* @return bool
*/
public function check($token, $marker, array $args = [])
public function verify($token, $marker, array $args = [])
{
return is_string($token)
&& preg_match('%f(\d+)$%D', $token, $matches)
@ -59,5 +58,4 @@ class Csrf
&& $matches[1] + 1800 > time()
&& hash_equals($this->create($marker, $args, $matches[1]), $token);
}
}

View file

@ -37,7 +37,7 @@ class Online
protected $user;
/**
* Контролер
* Конструктор
* @param array $config
* @param DB $db
* @param User $user

View file

@ -33,7 +33,7 @@ class Auth extends Page
{
$this->c->get('Lang')->load('login');
if ($this->c->get('Csrf')->check($args['token'], 'Logout', $args)) {
if ($this->c->get('Csrf')->verify($args['token'], 'Logout', $args)) {
$user = $this->c->get('user');
$this->c->get('UserCookie')->deleteUserCookie();
@ -43,7 +43,7 @@ class Auth extends Page
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Logout redirect'));
}
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Bad request'));
return $this->c->get('Redirect')->setPage('Index')->setMessage(__('Bad token'));
}
/**
@ -89,36 +89,33 @@ class Auth extends Page
{
$this->c->get('Lang')->load('login');
$username = $this->c->get('Request')->postStr('username', '');
$password = $this->c->get('Request')->postStr('password', '');
$token = $this->c->get('Request')->postStr('token');
$save = $this->c->get('Request')->postStr('save');
$v = $this->c->get('Validator');
$v->setRules([
'token' => 'token:Login',
'redirect' => 'referer:Index',
'username' => ['required|string|min:2|max:25', __('Username')],
'password' => ['required|string', __('Password')],
'save' => 'checkbox',
]);
$redirect = $this->c->get('Request')->postStr('redirect', '');
$redirect = $this->c->get('Router')->validate($redirect, 'Index');
$ok = $v->validation($_POST);
$data = $v->getData();
$this->iswev = $v->getErrors();
$args = [
'_username' => $username,
'_redirect' => $redirect,
'_save' => $save,
];
if (! $this->c->get('Csrf')->check($token, 'Login')) {
$this->iswev['e'][] = __('Bad token');
return $this->login($args);
}
if (empty($username) || empty($password)) {
if ($ok && ! $this->loginProcess($data['username'], $data['password'], $data['save'])) {
$this->iswev['v'][] = __('Wrong user/pass');
return $this->login($args);
$ok = false;
}
if (! $this->loginProcess($username, $password, ! empty($save))) {
$this->iswev['v'][] = __('Wrong user/pass');
return $this->login($args);
if ($ok) {
return $this->c->get('Redirect')->setUrl($data['redirect'])->setMessage(__('Login redirect'));
} else {
return $this->login([
'_username' => $data['username'],
'_redirect' => $data['redirect'],
'_save' => $data['save'],
]);
}
return $this->c->get('Redirect')->setUrl($redirect)->setMessage(__('Login redirect'));
}
/**
@ -196,7 +193,7 @@ class Auth extends Page
}
$this->titles = [
__('Request pass'),
__('Password reset'),
];
$this->data = [
'email' => $args['_email'],
@ -215,43 +212,43 @@ class Auth extends Page
{
$this->c->get('Lang')->load('login');
$token = $this->c->get('Request')->postStr('token');
$email = $this->c->get('Request')->postStr('email');
$v = $this->c->get('Validator');
$v->setRules([
'token' => 'token:Forget',
'email' => 'required|email',
])->setMessages([
'email' => __('Invalid email'),
]);
$args = [
'_email' => $email,
];
$ok = $v->validation($_POST);
$data = $v->getData();
$this->iswev = $v->getErrors();
if (! $this->c->get('Csrf')->check($token, 'Forget')) {
$this->iswev['e'][] = __('Bad token');
return $this->forget($args);
if ($ok && ($user = $this->c->get('UserMapper')->getUser($data['email'], 'email')) === null) {
$this->iswev['v'][] = __('Invalid email');
$ok = false;
}
if ($ok && ! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
$this->iswev['e'][] = __('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60));
$ok = false;
}
if (! $ok) {
return $this->forget([
'_email' => $data['email'],
]);
}
$mail = $this->c->get('Mail');
if (! $mail->valid($email)) {
$this->iswev['v'][] = __('Invalid email');
return $this->forget($args);
}
$user = $this->c->get('UserMapper')->getUser($email, 'email');
if (null == $user) {
$this->iswev['v'][] = __('Invalid email');
return $this->forget($args);
}
if (! empty($user->lastEmailSent) && time() - $user->lastEmailSent < 3600) {
$this->iswev['e'][] = __('Email flood', (int) (($user->lastEmailSent + 3600 - time()) / 60));
return $this->forget($args);
}
$mail->setFolder($this->c->getParameter('DIR_LANG'))
->setLanguage($user->language);
$key = 'p' . $this->c->get('Secury')->randomPass(75);
$link = $this->c->get('Router')->link('ChangePassword', ['email' => $email, 'key' => $key]);
$data = ['key' => $key, 'link' => $link];
$hash = $this->c->get('Secury')->hash($data['email'] . $key);
$link = $this->c->get('Router')->link('ChangePassword', ['email' => $data['email'], 'key' => $key, 'hash' => $hash]);
$tplData = ['link' => $link];
if ($mail->send($email, 'change_password.tpl', $data)) {
if ($mail->send($data['email'], 'change_password.tpl', $tplData)) {
$this->c->get('UserMapper')->updateUser($user->id, ['activate_string' => $key, 'last_email_sent' => time()]);
return $this->c->get('Message')->message(__('Forget mail', $this->config['o_admin_email']), false, 200);
} else {
@ -269,14 +266,19 @@ class Auth extends Page
$this->nameTpl = 'login/password';
$this->onlinePos = 'password';
// что-то пошло не так
if (! $this->c->get('Mail')->valid($args['email'])
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|| empty($user->activateString)
|| $user->activateString{0} !== 'p'
|| ! hash_equals($user->activateString, $args['key'])
) {
return $this->c->get('Message')->message(__('Bad request'), false);
if (isset($args['_ok'])) {
unset($args['_ok']);
} else {
// что-то пошло не так
if (! hash_equals($args['hash'], $this->c->get('Secury')->hash($args['email'] . $args['key']))
|| ! $this->c->get('Mail')->valid($args['email'])
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|| empty($user->activateString)
|| $user->activateString{0} !== 'p'
|| ! hash_equals($user->activateString, $args['key'])
) {
return $this->c->get('Message')->message(__('Bad request'), false);
}
}
$this->c->get('Lang')->load('login');
@ -300,14 +302,11 @@ class Auth extends Page
*/
public function changePassPost(array $args)
{
$token = $this->c->get('Request')->postStr('token');
$password = $this->c->get('Request')->postStr('password', '');
$password2 = $this->c->get('Request')->postStr('password2', '');
$this->c->get('Lang')->load('login');
// что-то пошло не так
if (! $this->c->get('Mail')->valid($args['email'])
if (! hash_equals($args['hash'], $this->c->get('Secury')->hash($args['email'] . $args['key']))
|| ! $this->c->get('Mail')->valid($args['email'])
|| ($user = $this->c->get('UserMapper')->getUser($args['email'], 'email')) === null
|| empty($user->activateString)
|| $user->activateString{0} !== 'p'
@ -316,23 +315,29 @@ class Auth extends Page
return $this->c->get('Message')->message(__('Bad request'), false);
}
if (! $this->c->get('Csrf')->check($token, 'ChangePassword', $args)) {
$this->iswev['e'][] = __('Bad token');
return $this->changePass($args);
}
if (mb_strlen($password) < 6) {
$this->iswev['v'][] = __('Pass too short');
return $this->changePass($args);
}
if ($password !== $password2) {
$this->iswev['v'][] = __('Pass not match');
return $this->changePass($args);
}
$this->c->get('UserMapper')->updateUser($user->id, ['password' => password_hash($password, PASSWORD_DEFAULT), 'activate_string' => null]);
$this->c->get('Lang')->load('profile');
$v = $this->c->get('Validator');
$v->setRules([
'token' => 'token:ChangePassword',
'password' => ['required|string|min:8', __('New pass')],
'password2' => 'required|same:password',
])->setArguments([
'token' => $args,
])->setMessages([
'password2' => __('Pass not match'),
]);
if (! $v->validation($_POST)) {
$this->iswev = $v->getErrors();
$args['_ok'] = true;
return $this->changePass($args);
}
$data = $v->getData();
$this->c->get('UserMapper')->updateUser($user->id, ['password' => password_hash($data['password'], PASSWORD_DEFAULT), 'activate_string' => null]);
$this->iswev['s'][] = __('Pass updated');
return $this->login([]);
return $this->login(['_redirect' => $this->c->get('Router')->link('Index')]);
}
}

423
app/Models/Validator.php Normal file
View file

@ -0,0 +1,423 @@
<?php
namespace ForkBB\Models;
use R2\DependencyInjection\ContainerInterface;
use RuntimeException;
class Validator
{
const T_UNKNOWN = 0;
const T_STRING = 1;
const T_NUMERIC = 2;
const T_INT = 3;
const T_ARRAY = 4;
/**
* Контейнер
* @var ContainerInterface
*/
protected $c;
/**
* @var array
*/
protected $rules;
/**
* @var array
*/
protected $data;
/**
* @var array
*/
protected $arguments;
/**
* @var array
*/
protected $messages;
/**
* @var array
*/
protected $aliases;
/**
* @var array
*/
protected $errors;
/**
* Тип текущего поля при валидации
* @var int
*/
protected $curType;
/**
* Конструктор
* @param ContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->c = $container;
}
/**
* Установка правил проверки
* @param array $list
* @return Validator
* @throws RuntimeException
*/
public function setRules(array $list)
{
$this->rules = [];
$this->data = [];
$this->alias = [];
$this->errors = [];
$this->arguments = [];
foreach ($list as $field => $raw) {
$rules = [];
// псевдоним содержится в списке правил
if (is_array($raw)) {
$this->aliases[$field] = $raw[1];
$raw = $raw[0];
}
// перебор правил для текущего поля
$rawRules = explode('|', $raw);
foreach ($rawRules as $rule) {
$tmp = explode(':', $rule, 2);
if (! method_exists($this, $tmp[0] . 'Rule')) {
throw new RuntimeException('Rule not found');
}
$rules[$tmp[0]] = isset($tmp[1]) ? $tmp[1] : '';
}
$this->rules[$field] = $rules;
}
return $this;
}
/**
* Установка дополнительных аргументов для конкретных "имя поля"."имя правила".
* @param array $arguments
* @return Validator
*/
public function setArguments(array $arguments)
{
$this->arguments = $arguments;
return $this;
}
/**
* Установка сообщений для конкретных "имя поля"."имя правила".
* @param array $messages
* @return Validator
*/
public function setMessages(array $messages)
{
$this->messages = $messages;
return $this;
}
/**
* Установка псевдонимов имен полей для сообщений об ошибках
* @param array $aliases
* @return Validator
*/
public function setAliases(array $aliases)
{
$this->aliases = $aliases;
return $this;
}
/**
* Проверка данных
* Удачная проверка возвращает true
* @param array $raw
* @return bool
* @throws \RuntimeException
*/
public function validation(array $raw)
{
if (empty($this->rules)) {
throw new RuntimeException('Rules not found');
}
$ok = true;
$this->errors = [];
// перебор всех полей
foreach ($this->rules as $field => $rules) {
$error = false;
$this->curType = self::T_UNKNOWN;
// обязательное поле отсутствует
if (! isset($raw[$field]) && isset($rules['required'])) {
$rule = 'required';
$attr = $rules['required'];
$args = $this->getArguments($field, $rule);
list($value, $error) = $this->requiredRule('', $attr, $args);
} else {
$value = isset($raw[$field])
? $this->c->get('Secury')->replInvalidChars($raw[$field])
: null;
// перебор правил для текущего поля
foreach ($rules as $rule => $attr) {
$args = $this->getArguments($field, $rule);
$method = $rule . 'Rule';
list($value, $error) = $this->$method($value, $attr, $args);
// ошибок нет
if (false === $error) {
continue;
}
break;
}
}
$ok = $this->error($error, $field, $rule, $attr, $ok);
$this->data[$field] = $value;
}
return $ok;
}
/**
* Получение дополнительных аргументов
* @param string $field
* @param string $field
* @return mixed
*/
protected function getArguments($field, $rule)
{
if (isset($this->arguments[$field . '.'. $rule])) {
return $this->arguments[$field . '.'. $rule];
} elseif (isset($this->arguments[$field])) {
return $this->arguments[$field];
} else {
return null;
}
}
/**
* Обработка ошибки
* @param mixed $error
* @param string $field
* @param string $rule
* @param string $attr
* @param bool $ok
* return bool
*/
protected function error($error, $field, $rule, $attr, $ok)
{
if (is_bool($error)) {
return $ok;
}
// псевдоним имени поля
$alias = isset($this->aliases[$field]) ? $this->aliases[$field] : $field;
// текст ошибки
if (isset($this->messages[$field . '.' . $rule])) {
$error = $this->messages[$field . '.' . $rule];
} elseif (isset($this->messages[$field])) {
$error = $this->messages[$field];
}
$type = 'v';
// ошибка содержит тип
if (is_array($error)) {
$type = $error[1];
$error = $error[0];
}
$this->errors[$type][] = __($error, [':alias' => $alias, ':attr' => $attr]);
return false;
}
/**
* Возвращает проверенные данные
* Поля с ошибками содержат значения по умолчанию или значения с ошибками
* @return array
* @throws \RuntimeException
*/
public function getData()
{
if (empty($this->data)) {
throw new RuntimeException('Data not found');
}
return $this->data;
}
/**
* Возращает массив ошибок
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* Правило "required"
* @param mixed $value
* @param string $attrs
* @param mixed $args
* @return array
*/
protected function requiredRule($value, $attr, $args)
{
$f = function () use ($value) {
if (is_string($value)) {
$this->curType = self::T_STRING;
return isset($value{0});
} elseif (is_array($value)) {
$this->curType = self::T_ARRAY;
return ! empty($value);
} else {
return null !== $value;
}
};
if ($f()) {
if (is_numeric($value)) {
if (is_int(0 + $value)) {
$this->curType = self::T_INT;
} else {
$this->curType = self::T_NUMERIC;
}
}
return [$value, false];
} else {
return [$attr, 'The :alias is required'];
}
}
protected function stringRule($value, $attr)
{
if (is_string($value)) {
$this->curType = self::T_STRING;
return [$value, false];
} else {
return [$attr, 'The :alias must be string'];
}
}
protected function numericRule($value, $attr)
{
if (is_numeric($value)) {
$this->curType = self::T_NUMERIC;
return [0 + $value, false];
} else {
return [$attr, 'The :alias must be numeric'];
}
}
protected function intRule($value, $attr)
{
if (is_numeric($value) && is_int(0 + $value)) {
$this->curType = self::T_INT;
return [(int) $value, false];
} else {
return [$attr, 'The :alias must be integer'];
}
}
protected function arrayRule($value, $attr)
{
if (is_array($value)) {
$this->curType = self::T_ARRAY;
return [$value, false];
} else {
return [$attr, 'The :alias must be array'];
}
}
protected function minRule($value, $attr)
{
switch ($this->curType) {
case self::T_STRING:
if (mb_strlen($value) < $attr) {
return [$value, 'The :alias minimum is :attr characters'];
}
break;
case self::T_NUMERIC:
case self::T_INT:
if ($value < $attr) {
return [$value, 'The :alias minimum is :attr'];
}
break;
case self::T_ARRAY:
if (count($value) < $attr) {
return [$value, 'The :alias minimum is :attr elements'];
}
break;
default:
return ['', 'The :alias minimum is :attr'];
break;
}
return [$value, false];
}
protected function maxRule($value, $attr)
{
switch ($this->curType) {
case self::T_STRING:
if (mb_strlen($value) > $attr) {
return [$value, 'The :alias maximum is :attr characters'];
}
break;
case self::T_NUMERIC:
case self::T_INT:
if ($value > $attr) {
return [$value, 'The :alias maximum is :attr'];
}
break;
case self::T_ARRAY:
if (count($value) > $attr) {
return [$value, 'The :alias maximum is :attr elements'];
}
break;
default:
return ['', 'The :alias maximum is :attr'];
break;
}
return [$value, false];
}
protected function tokenRule($value, $attr, $args)
{
if (! is_array($args)) {
$args = [];
}
if (is_string($value) && $this->c->get('Csrf')->verify($value, $attr, $args)) {
return [$value, false];
} else {
return ['', ['Bad token', 'e']];
}
}
protected function checkboxRule($value, $attr)
{
return [! empty($value), false]; //????
}
protected function refererRule($value, $attr, $args)
{
if (! is_array($args)) {
$args = [];
}
return [$this->c->get('Router')->validate($value, $attr), false];
}
protected function emailRule($value, $attr)
{
if ($this->c->get('Mail')->valid($value)) {
return [$value, false];
} else {
if (! is_string($value)) {
$value = (string) $value;
}
return [$value, 'The :alias is not valid email'];
}
}
protected function sameRule($value, $attr)
{
if (isset($this->data[$attr]) && $value === $this->data[$attr]) {
return [$value, false];
} else {
return [$value, 'The :alias must be same with original'];
}
}
}

View file

@ -24,10 +24,10 @@ msgstr "Logged in successfully. Redirecting …"
msgid "Logout redirect"
msgstr "Logged out. Redirecting …"
msgid "Request pass"
msgstr "Request password"
msgid "Password reset"
msgstr "Password reset"
msgid "Request pass info"
msgid "Password reset info"
msgstr "An email will be sent to the specified address with instructions on how to change your password."
msgid "Not registered"
@ -43,10 +43,7 @@ msgid "Error mail"
msgstr "When sending email there was an error. Try later or contact the forum administrator at <a href=\"mailto:%1$s\">%1$s</a>."
msgid "Email flood"
msgstr "This account has already requested a password reset in the past hour. Please wait %s minutes before requesting a new password again."
msgid "Pass too short"
msgstr "Passwords must be at least 6 characters long."
msgstr "This account has already requested a password reset in the past hour. Please wait %s minutes before trying again."
msgid "Pass not match"
msgstr "Passwords do not match."

View file

@ -79,7 +79,7 @@ msgid "Confirm new pass"
msgstr "Confirm new password"
msgid "Pass info"
msgstr "Passwords must be at least 6 characters long. Passwords are case sensitive."
msgstr "Passwords must be at least 8 characters long. Passwords are case sensitive."
msgid "Email key bad"
msgstr "The specified email activation key was incorrect or has expired. Please re-request change of email address. If that fails, contact the forum administrator at"

View file

@ -24,11 +24,11 @@ msgstr "Успешный вход. Переадресация &hellip;"
msgid "Logout redirect"
msgstr "Выход произведён. Переадресация &hellip;"
msgid "Request pass"
msgstr "Восстановление пароля"
msgid "Password reset"
msgstr "Сброс пароля"
msgid "Request pass info"
msgstr "Инструкция по смене пароля будет выслана на указанный адрес."
msgid "Password reset info"
msgstr "Инструкция по смене пароля будет выслана на указанный почтовый адрес."
msgid "Not registered"
msgstr "Ещё не зарегистрированы?"
@ -43,10 +43,7 @@ msgid "Error mail"
msgstr "При отправки письма возникла ошибка. Попробуйте позже или свяжитесь с администратором форума по адресу <a href=\"mailto:%1$s\">%1$s</a>."
msgid "Email flood"
msgstr "Для этой учетной записи недавно уже запрашивали новый пароль. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
msgid "Pass too short"
msgstr "Пароль должен состоять минимум из 6 символов."
msgstr "Для этой учетной записи недавно уже запрашивали сброс пароля. Пожалуйста, подождите %s минут, прежде чем повторить попытку."
msgid "Pass not match"
msgstr "Пароли не совпадают."

View file

@ -79,7 +79,7 @@ msgid "Confirm new pass"
msgstr "Ещё раз"
msgid "Pass info"
msgstr "Пароль должен состоять минимум из 6 символов. Пароль чувствителен к регистру вводимых букв."
msgstr "Пароль должен состоять минимум из 8 символов. Пароль чувствителен к регистру вводимых букв."
msgid "Email key bad"
msgstr "Указанный ключ активации почтового адреса неверен или истек срок его действия. Пожалуйста, повторно запросите смену почтового адреса. Если ничего не получится, то свяжитесь с администрацией; почтовый адрес для связи"

View file

@ -1,12 +1,12 @@
@extends('layouts/main')
<section class="f-main f-login">
<div class="f-wdiv">
<h2>{!! __('Request pass') !!}</h2>
<h2>{!! __('Password reset') !!}</h2>
<form class="f-form" method="post" action="{!! $formAction !!}">
<input type="hidden" name="token" value="{!! $formToken !!}">
<label class="f-child1" for="id-email">{!! __('Email') !!}</label>
<input required id="id-email" type="text" name="email" value="{{ $email }}" maxlength="80" autofocus="autofocus" spellcheck="false" tabindex="1">
<label class="f-child2">{!! __('Request pass info') !!}</label>
<label class="f-child2">{!! __('Password reset info') !!}</label>
<input class="f-btn" type="submit" name="submit" value="{!! __('Submit') !!}" tabindex="2">
</form>
</div>

View file

@ -5,9 +5,9 @@
<form class="f-form" method="post" action="{!! $formAction !!}">
<input type="hidden" name="token" value="{!! $formToken !!}">
<label class="f-child1" for="id-password">{!! __('New pass') !!}</label>
<input required id="id-password" type="password" name="password" pattern=".{6,}" autofocus="autofocus" tabindex="1">
<input required id="id-password" type="password" name="password" pattern=".{8,}" autofocus="autofocus" tabindex="1">
<label class="f-child1" for="id-password2">{!! __('Confirm new pass') !!}</label>
<input required id="id-password2" type="password" name="password2" pattern=".{6,}" tabindex="2">
<input required id="id-password2" type="password" name="password2" pattern=".{8,}" tabindex="2">
<label class="f-child2">{!! __('Pass info') !!}</label>
<input class="f-btn" type="submit" name="login" value="{!! __('Save') !!}" tabindex="3">
</form>

View file

@ -2083,6 +2083,8 @@ function __($data, ...$args)
if (empty($args)) {
return $tr;
} elseif (is_array($args[0])) {
return strtr($tr, $args[0]);
} else {
return sprintf($tr, ...$args);
}