Использование базового TOTP через мобильное приложение вместо существующей реализации второго пароля на javascript.

This commit is contained in:
Ivor Barhansky 2024-05-09 19:19:14 +03:00
parent 85b74015b7
commit 244e081014
7 changed files with 260 additions and 494 deletions

View File

@ -0,0 +1,69 @@
<?php
namespace Core;
readonly class TOTP
{
private const BASE32CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567'; // RFC 4648 Base32
public function __construct(private string $secret)
{
}
public static function otpSecret($uniqueString, $length = 20): string
{
// Уникальная строка + текущее время в микросекундах
$seed = $uniqueString . microtime(true);
// Хэшируем сид для более случайного распределения
$seed = hash('sha256', $seed);
$secret = '';
$max = strlen(self::BASE32CHARS) - 1;
// Генерируем случайную строку нужной длины
for ($i = 0; $i < $length; $i++) {
$index = hexdec(substr($seed, $i, 2)) % $max; // Получаем индекс символа из хэшированного сида
$secret .= self::BASE32CHARS[$index];
}
return $secret;
}
public function generate(int $digits = 6, int $timeStep = 30): string
{
$time = floor(time() / $timeStep);
$secretKey = $this->base32_decode($this->secret);
$binaryTime = pack('N*', 0) . pack('N*', $time);
$hash = hash_hmac('sha1', $binaryTime, $secretKey, true);
$offset = ord($hash[strlen($hash) - 1]) & 0x0F;
$otp = (
((ord($hash[$offset]) & 0x7F) << 24) |
((ord($hash[$offset + 1]) & 0xFF) << 16) |
((ord($hash[$offset + 2]) & 0xFF) << 8) |
(ord($hash[$offset + 3]) & 0xFF)
) % 10 ** $digits;
return str_pad((string)$otp, $digits, '0', STR_PAD_LEFT);
}
private function base32_decode(string $input): string
{
$base32charsFlipped = array_flip(str_split(self::BASE32CHARS));
$output = '';
$v = 0;
$vbits = 0;
for ($i = 0, $j = strlen($input); $i < $j; $i++) {
$v <<= 5;
if ($input[$i] == '=') continue;
$v += $base32charsFlipped[$input[$i]];
$vbits += 5;
if ($vbits >= 8) {
$vbits -= 8;
$output .= chr(($v & (0xFF << $vbits)) >> $vbits);
}
}
return $output;
}
}

View File

@ -6,30 +6,24 @@ use Core\Config;
use Core\Db;
use Helper\Mail;
use PassGen;
use UserIp;
class Confirmation
{
/**
* Для однотипных писем с подтверждением.
* @param array $userinfo Данные из (User)->info.
* @param mixed $value Новое значение
* @param string $value Новое значение
* @param ?int $code Проверочный код
* @param string $type Тип меняемого значения. С маленькой буквы, именительный падеж.
* @return void
*/
public static function byEmail(array $userinfo, string $type, $value, ?int $code = null)
public static function byEmail(array $userinfo, string $type, string $value, ?int $code = null): void
{
if ($type === 'pass2' && is_null($code)) {
self::pass2ByEmailCustom($userinfo, $value);
return;
}
$ip = UserIp::get();
$date = date('d.m.y H:i');
$https = Config::get('https');
$support = Config::get('support');
$activationLink = 'https://' . $userinfo['city'] . Config::get('host') .
"/confirm.php?id={$userinfo['id']}&code=$code";
$activationLink = Config::get('https') . "/confirm.php?id={$userinfo['id']}&code=$code";
$fulllogin = $userinfo['login'] . "[{$userinfo['level']}]";
Mail::send(
$userinfo['mail'],
@ -55,31 +49,7 @@ class Confirmation
);
}
private static function pass2ByEmailCustom(array $userinfo, string $pass2)
{
$ip = UserIp::get();
$fulllogin = $userinfo['login'] . "[{$userinfo['level']}]";
Mail::send(
$userinfo['mail'],
<<<HTML
<html lang="ru">
<head><title>Второй пароль от персонажа $fulllogin.</title></head>
<body>
Вами, с IP адреса - $ip, был установлен второй пароль в игре Бойцовский Клуб.<br>
Если это были не Вы, свяжитесь с администрацией сайта.<br><br>
------------------------------------------------------------------<br>
Ваш логин | {$userinfo['login']}<br>
Второй пароль | ' . $pass2 . '<br>
------------------------------------------------------------------<br>
<br><br>Желаем Вам приятной игры.<br><br><i>Администрация</i>
</body>
HTML,
"Второй пароль от персонажа $fulllogin"
);
}
public static function userRegistrationCodeByEmail(string $email, string $login)
public static function userRegistrationCodeByEmail(string $email, string $login): void
{
$code = PassGen::intCode(4);
Db::sql('insert into secure_code (email, code, time) values (?,?,unix_timestamp())', [$email, $code]);

View File

@ -57,28 +57,5 @@ class Password
}
return $this->info['pass'];
}
public function changeSecond(?int $passLength): array
{
if (in_array($passLength, [4, 6, 8])) {
$query = 'update users set pass2 = ? where id = ?';
$pass2 = PassGen::intCode($passLength);
$args = [
password_hash($pass2, PASSWORD_DEFAULT),
$this->info['id'],
];
Confirmation::byEmail($this->info, 'pass2', $pass2);
$hash = $args[0];
} else {
$query = 'update users set pass2 = default where id = ?';
$args = [$this->info['id']];
}
Db::sql($query, $args);
return [
'pass2' => $pass2 ?? '',
'hash' => $hash ?? null,
];
}
}

302
enter.php
View File

@ -3,6 +3,8 @@
use Core\Config;
use Core\Database;
use Core\Db;
use Core\TOTP;
use JetBrains\PhpStorm\NoReturn;
use User\Password;
use User\UserIp;
@ -15,43 +17,36 @@ require_once __DIR__ . DIRECTORY_SEPARATOR . '_incl_data/autoload.php';
Database::init();
define('IP', UserIp::get());
$chat = new Chat();
$login = $_SESSION['login'] ?? '';
$password = '';
$otp = '';
if (isset($_GET['login'])) {
$_POST['login'] = $_GET['login'];
$_POST['pass'] = $_GET['pass'];
$_POST['code'] = $_GET['code'];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['login'])) {
$login = $_POST['login'];
}
if (isset($_POST['password'])) {
$password = $_POST['password'];
}
if (isset($_POST['otp'])) {
$otp = $_POST['otp'];
}
}
if (isset($_POST['psw'])) {
$_POST['pass'] = $_POST['psw'];
}
if (isset($_SESSION['login'])) {
$_POST['login'] = $_SESSION['login'];
$_POST['pass'] = $_SESSION['pass'];
}
function error($e)
#[NoReturn] function error($e): void
{
die(
'
<link rel="stylesheet" href="error.css">
<div class="text-wrapper">
<div class="title" data-content="Ошибка">
Ошибка!!
$returnLink = Config::get('https');
$html = <<<HTML
<link rel="stylesheet" href="error.css">
<div class="text-wrapper">
<div class="title" data-content="Ошибка">Ошибка!!</div>
<div class="subtitle">$e</div>
<div class="buttons"><a class="button" href="$returnLink">Вернуться назад</a></div>
</div>
<div class="subtitle">
' . $e . '
</div>
<div class="buttons">
<a class="button" href="' . Config::get('https') . '">Вернуться назад</a>
</div>
</div>
'
);
HTML;
exit($html);
}
$u = Db::getRow(
@ -60,185 +55,79 @@ $u = Db::getRow(
users.login,
auth,
pass,
pass2,
users.city,
totp,
users.ip,
ipreg,
admin,
online,
banned,
host_reg,
timereg,
securetime,
users_delo.text as block_reason
from users
left join users_delo on users.id = users_delo.uid
where users.login = ?',
[$_POST['login']]
[$login]
);
$auth = Db::getValue('select id from logs_auth where uid = ? and ip = ?', [$u['id'], IP]);
if (!isset($u['id'])) {
error('Логин "' . $_POST['login'] . '" не найден в базе.');
} elseif ($u['banned'] > 0) {
if (empty($_SESSION['login'])) {
if (!isset($u['id'])) {
error('Логин "' . $login . '" не найден в базе.');
} elseif ($u['banned'] > 0) {
$blockstr = "Персонаж <b>{$u['login']}</b> заблокирован.";
$blockstr .= $u['block_reason'] ? "Причина блокировки: {$u['block_reason']}<br><br>" : '<br><br>';
error($blockstr);
} elseif (!Password::isGood($_POST['pass'], $u['pass'], $u['login'])) {
error("Неверный пароль к персонажу {$u['login']}.");
} elseif (!Password::isGood($password, $u['pass'], $u['login'])) {
Db::sql(
'insert into logs_auth (uid, ip, browser, type, time) values (?,?,?,3,unix_timestamp())',
[$u['id'], IP, $_SERVER['HTTP_USER_AGENT']]
);
} else {
//Второй пароль
if (!empty($u['pass2'])) {
$_SESSION['login'] = $_POST['login'];
$_SESSION['pass'] = $_POST['pass'];
$good2 = false;
$koko = '';
if (password_verify($_POST['code'], $u['pass2'])) {
$good2 = true;
unset($_SESSION['login'], $_SESSION['pass']);
} else {
if (isset($_POST['code'])) {
$koko = 'Неверный второй пароль<br>';
}
setcookie('login', '', time() - 60 * 60 * 24, '', Config::get('host'));
error("Неверный пароль к персонажу {$u['login']}.");
}
if ($koko) {
$koko = '<b style="color: red">' . $koko . '</b>';
$_SESSION['login'] = $u['login'];
if (!empty($u['totp'])) {
$_SESSION['totp'] = new TOTP($u['totp']);
}
if (!$good2) {
}
if (!empty($_SESSION['totp']) && !empty($_SESSION['login'])) {
if (empty($otp)) {
?>
<!Doctype html>
<HTML lang="ru">
<HEAD>
<link rel=stylesheet type="text/css">
<meta name="msapplication-config" content="browserconfig.xml"/>
<TITLE>Второй пароль</TITLE>
</HEAD>
<body style="background-color: #dfdfde;">
<H3>Запрос второго пароля к персонажу.</H3>
<?= $koko ?>
<div style="text-align: center">
<br>
<br>
<img id="pass" onClick="" width="295" src="i/pin/e0.png" alt="pass">
<br>
<br>
<img id="p1" onClick="" src="" alt="p1">
<img id="p2" onClick="" src="" alt="p2">
<img id="p3" onClick="" src="" alt="p3">
<br>
<img id="p4" onClick="" src="" alt="p4">
<img id="p5" onClick="" src="" alt="p5">
<img id="p6" onClick="" src="" alt="p6">
<br>
<img id="p7" onClick="" src="" alt="p7">
<img id="p8" onClick="" src="" alt="p8">
<img id="p9" onClick="" src="" alt="p9">
<br>
<img onClick="keypush(12);" src="i/pin/12.png" alt="back">
<img id="p0" name="image" onClick="" src="" alt="nan">
<img onClick="keypush(11);" src="i/pin/11.png" alt="ok">
<br>
</div>
</BODY>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
var dopass = '';
var tdopass = '';
var lenth = 0;
randomp();
function randomp() {
var ss = [];
var n = 0;
while (n < 10) {
ss[n] = n;
n++;
}
var i = 0;
var k = 0;
var m = 0;
var tmpp = 0;
while (i < 10) {
k = getRandomInt(10);
m = getRandomInt(10);
if (k != m) {
tmpp = ss[k];
ss[k] = ss[m];
ss[m] = tmpp;
i++;
}
}
n = 10;
while (n > -1) {
n = n - 1;
document.getElementById('p' + n).setAttribute("src", "i/pin/" + ss[n] + ".png");
document.getElementById('p' + n).setAttribute("onClick", "keypush(" + ss[n] + ");");
}
}
function getRandomInt(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function keypush(n) {
if (n == 12) {
if (lenth > 0) {
dopass = '';
lenth = 0;
document.getElementById('pass').setAttribute("src", "i/pin/e" + lenth + ".png");
}
} else if (n == 11) {
var $_POST = <?= json_encode($_POST); ?>;
window.location.replace("/enter.php?code=" + dopass + "&login=" + $_POST['login'] + "&pass=" + $_POST['pass']);
} else {
if (lenth < 8) {
dopass = dopass + '' + n;
lenth++;
document.getElementById('pass').setAttribute("src", "i/pin/e" + lenth + ".png");
}
}
}
</script>
</HTML>
<!doctype html>
<html lang="ru">
<head>
<title>Второй пароль</title>
</head>
<body>
<form method="post">
<label for="otp">Одноразовый код:</label><br>
<input name="otp" id="otp" minlength="6" maxlength="6" size="6" placeholder="000000" required><br>
<input type="submit">
</form>
</body>
</html>
<?php
die();
}
exit();
}
if (!Db::getValue('select count(*) from stats where id = ?', [$u['id']])) {
if ($_SESSION['totp']->generate() !== $otp) {
unset($_SESSION['login'], $_SESSION['totp']);
error('Неверный одноразовый код!');
}
}
if (!Db::getValue('select count(*) from stats where id = ?', [$u['id']])) {
Db::sql('insert into stats (id, stats) values (?,?)', [$u['id'], 's1=3|s2=3|s3=3|s4=3|rinv=40|m9=5|m6=10']);
}
if (!Db::getValue('select count(*) from online where uid = ?', [$u['id']])) {
}
if (!Db::getValue('select count(*) from online where uid = ?', [$u['id']])) {
Db::sql('insert into online (uid, timeStart) values (?,unix_timestamp())', [$u['id']]);
}
}
if (isset($_COOKIE['login'])) {
if (isset($_COOKIE['login'])) {
setcookie('login', '', time() - 60 * 60 * 24, '', Config::get('host'));
}
}
//мульты
if ($u['admin'] === 0) {
//мульты
if ($u['admin'] === 0) {
$ipm1 = Db::getValue(
'select ip from logs_auth where uid = ? and ip != ? order by id limit 1',
[$u['id'], $u['ip']]
@ -256,39 +145,38 @@ if (!isset($u['id'])) {
Db::sql('insert into mults (uid, uid2, ip) VALUES (?,?,?)', [$u['id'], $item['uid'], $item['ip']]);
}
}
}
}
if (isset($_COOKIE['ip']) && $_COOKIE['ip'] != IP) {
if (isset($_COOKIE['ip']) && $_COOKIE['ip'] != IP) {
Db::sql(
'insert into logs_auth (uid, ip, browser, type, time) VALUES (?,?,?,1,unix_timestamp())',
[$u['id'], $_COOKIE['ip'], $_SERVER['HTTP_USER_AGENT']]
);
}
}
setcookie('login', $_POST['login'] ?? '', time() + 60 * 60 * 24 * 7, '', Config::get('host'));
setcookie('ip', IP, time() + 60 * 60 * 24 * 150, '');
setcookie('login', $_POST['login'] ?? '', time() + 60 * 60 * 24 * 7, '', Config::get('host'));
setcookie('ip', IP, time() + 60 * 60 * 24 * 150, '');
if ($u['online'] < time() - 520) {
$sp = Db::getRows('select room, city, login from users where online > unix_timestamp() - 600 and id in (select user from friends where friend = ?)', [$u['id']]);
if ($u['online'] < time() - 520) {
$sp = Db::getRows('select room, login from users where online > unix_timestamp() - 600 and id in (select user from friends where friend = ?)', [$u['id']]);
foreach ($sp as $usr) {
$chatDto = new ChatMessage();
$chatDto->setRoom($usr['room']);
$chatDto->setCity($usr['city']);
$chatDto->setTo($usr['login']);
$chatDto->setText('Вас приветствует: <b>' . $u['login'] . '</b>.');
$chatDto->setType(6);
$chat->sendMsg($chatDto);
}
}
}
$apu = '';
Db::sql('update dump set ver = 1, upd = 2 where uid = ?', [$u['id']]);
$apu = '';
Db::sql('update dump set ver = 1, upd = 2 where uid = ?', [$u['id']]);
if (
if (
$u['auth'] != md5($u['login'] . 'AUTH' . IP) ||
$_COOKIE['auth'] != md5($u['login'] . 'AUTH' . IP) ||
$u['auth'] == '' || $u['auth'] == '0'
) {
) {
if (
$u['auth'] != '' &&
$u['auth'] != '0' &&
@ -302,17 +190,19 @@ if (!isset($u['id'])) {
}
$apu = "auth = '" . md5($u['login'] . 'AUTH' . IP) . "',";
setcookie('auth', md5($u['login'] . 'AUTH' . IP), time() + 60 * 60 * 24 * 365, '', Config::get('host'));
}
$ipnew = IP;
Db::sql('insert into logs_auth (uid, ip, browser, time) values (?,?,?,unix_timestamp())', [
$u['id'], IP, $_SERVER['HTTP_USER_AGENT'],
]);
Db::sql("update users set $apu ip = ?, dateEnter = ?, online = unix_timestamp() where id = ?", [$ipnew, $_SERVER['HTTP_USER_AGENT'], $u['id']]);
$_SESSION['uid'] = $u['id'];
header('location: /bk');
exit();
}
$ipnew = IP;
Db::sql('insert into logs_auth (uid, ip, browser, time) values (?,?,?,unix_timestamp())', [
$u['id'], IP, $_SERVER['HTTP_USER_AGENT'],
]);
Db::sql("update users set $apu ip = ?, dateEnter = ?, online = unix_timestamp() where id = ?", [$ipnew, $_SERVER['HTTP_USER_AGENT'], $u['id']]);
$_SESSION['uid'] = $u['id'];
unset($_SESSION['login'], $_SESSION['totp']);
header('location: /bk');
exit();

110
gate.php
View File

@ -1,110 +0,0 @@
<?php
define('GAME',true);
include_once('_incl_data/__config.php');
include_once('_incl_data/class/__db_connect.php');
if( isset($_GET['md5']) ) {
$_GET['in'] = 1;
}
if( isset($_GET['in']) ) {
$_GET['ref'] = 7;
$login = $_GET['login'];
$pass = $_GET['pass'];
$md5 = md5( 'GATE_IN_DATA::'.$_GET['login'].$_GET['pass'].$_GET['exp'].$_GET['align'].$_GET['clan_prava'].$_GET['bithday'].$_GET['clan'].$_GET['sex'].$_GET['win'].$_GET['lose'].$_GET['nich'] );
if( $md5 != $_GET['md5'] ) {
unset($_GET['in']);
}else{
echo 'Нельзя создать т.к. не верный ключ и данные!';
}
if( $_GET['exp'] > 300000 ) {
$_GET['exp'] = 300000;
}
if( $_GET['clan'] == 1 ) {
$_GET['clan'] = 0;
$_GET['align'] = 0;
$_GET['clan_prava'] = 0;
}
if( $_GET['clan'] > 1 ) {
$_GET['clan'] += 2;
}
$usr = mysql_fetch_array(mysql_query('SELECT * FROM `users` WHERE `login` = "'.mysql_real_escape_string($_GET['login']).'" LIMIT 1'));
if(isset($usr['id']) && isset($_GET['in'])) {
unset($_GET['in']);
setcookie('login',$_GET['login'], (time()+60*60*24*7) , '' , '.new-combats.com' );
setcookie('pass',$_GET['pass'], (time()+60*60*24*7) , '' , '.new-combats.com' );
setcookie('login',$_GET['login'], (time()+60*60*24*7) );
setcookie('pass',$_GET['pass'], (time()+60*60*24*7) );
header('location: /enter.php?login='.$_GET['login'].'&pass='.$_GET['pass'].'');
die();
}
}
if( isset($_GET['in']) ) {
//Создаем персонажа
if( (int)$_GET['ref'] > 0 ) {
mysql_query("UPDATE `users` SET `referals` = `referals` + 1 WHERE `id` = '".mysql_real_escape_string((int)$_GET['ref'])."' LIMIT 1");
}
$pass = md5($pass);
mysql_query('INSERT INTO `users` (`real`,`online`,`align`,`clan`,`clan_prava`,`win`,`lose`,`nich`,`sex`,`bithday`,`host_reg`,`pass`,`ip`,`ipreg`,`city`,`cityreg`,`room`,`timereg`) VALUES (
"1",
"'.time().'",
"'.mysql_real_escape_string($_GET['align']).'",
"'.mysql_real_escape_string($_GET['clan']).'",
"'.mysql_real_escape_string($_GET['clan_prava']).'",
"'.mysql_real_escape_string($_GET['win']).'",
"'.mysql_real_escape_string($_GET['lose']).'",
"'.mysql_real_escape_string($_GET['nich']).'",
"'.mysql_real_escape_string($_GET['sex']).'",
"'.mysql_real_escape_string($_GET['bithday']).'",
"'.mysql_real_escape_string(0+$_GET['ref']).'",
"'.mysql_real_escape_string($pass).'",
"'.mysql_real_escape_string(GetRealIpTest()).'",
"'.mysql_real_escape_string(GetRealIpTest()).'",
"capitalcity",
"capitalcity",
"0",
"'.time().'"
)');
$uid = mysql_insert_id();
if( $uid > 0 ) {
mysql_query('UPDATE `users` SET `login` = "'.mysql_real_escape_string($login).'" WHERE `id` = "'.$uid.'" LIMIT 1');
//Создаем статы персонажа
mysql_query("INSERT INTO `online` (`uid`,`timeStart`) VALUES ('".$uid."','".time()."')");
mysql_query("INSERT INTO `stats` (`id`,`stats`,`exp`) VALUES ('".$uid."','s1=3|s2=3|s3=3|s4=3|rinv=40|m9=5|m6=10','".mysql_real_escape_string($_GET['exp'])."')");
//мульты
$ipm1 = mysql_fetch_array(mysql_query('SELECT * FROM `logs_auth` WHERE `uid` = "'.mysql_real_escape_string($uid).'" AND `ip`!="'.mysql_real_escape_string(GetRealIpTest()).'" ORDER BY `id` ASC LIMIT 1'));
$ppl = mysql_query('SELECT * FROM `logs_auth` WHERE `ip`!="" AND (`ip` = "'.mysql_real_escape_string(GetRealIpTest()).'" OR `ip`="'.mysql_real_escape_string($ipm1['ip']).'" OR `ip`="'.mysql_real_escape_string($_COOKIE['ip']).'")');
while($spl = mysql_fetch_array($ppl))
{
$ml = mysql_fetch_array(mysql_query('SELECT `id` FROM `mults` WHERE (`uid` = "'.$spl['uid'].'" AND `uid2` = "'.$uid.'") OR (`uid2` = "'.$spl['uid'].'" AND `uid` = "'.$uid.'") LIMIT 1'));
if(!isset($ml['id']) && $spl['ip']!='' && $spl['ip']!='127.0.0.1')
{
mysql_query('INSERT INTO `mults` (`uid`,`uid2`,`ip`) VALUES ("'.$uid.'","'.$spl['uid'].'","'.$spl['ip'].'")');
}
}
mysql_query("INSERT INTO `logs_auth` (`uid`,`ip`,`browser`,`type`,`time`,`depass`) VALUES ('".$uid."','".mysql_real_escape_string(GetRealIpTest())."','".mysql_real_escape_string($_SERVER['HTTP_USER_AGENT'])."','1','".time()."','')");
//Обновяем таблицы
mysql_query("UPDATE `users` SET `online`='".time()."',`ip` = '".mysql_real_escape_string(GetRealIpTest())."' WHERE `uid` = '".$uid."' LIMIT 1");
if(!setcookie('login',$login, (time()+60*60*24*7) , '' , '.new-combats.com' ) || !setcookie('pass',$pass, (time()+60*60*24*7) , '' , '.new-combats.com' )) {
die('Ошибка сохранения cookie.');
}
header('location: /enter.php?login='.$_GET['login'].'&pass='.$_GET['pass'].'');
}
}
?>

View File

@ -6,11 +6,6 @@ if (!defined('GAME_VERSION')) {
require_once '_incl_data/autoload.php';
}
if (isset($_GET['time'])) {
echo time() . '<br>' . date('d.m.Y H:i:s', (int)$_GET['time']);
die();
}
header("Cache-Control: max-age=3600");
?>
<!DOCTYPE html>
@ -30,6 +25,7 @@ header("Cache-Control: max-age=3600");
flex-direction: column;
margin-top: 50px;
}
hr.incontent {
width: 32%;
border: 1px #1c1c1c solid;
@ -43,7 +39,7 @@ header("Cache-Control: max-age=3600");
<label for="first-name">Ваш Никнейм</label><br>
<input type="text" id="first-name" name="login" autocomplete="username"><br>
<label for="last-name">Ваш Пароль</label><br>
<input type="password" id="last-name" name="psw" autocomplete="current-password">
<input type="password" id="last-name" name="password" autocomplete="current-password">
<p>
<input type="submit" value="Войти в игру" class="btn btn-default">
</form>

View File

@ -3,6 +3,8 @@
/* @var $u User */
use Core\Config;
use Core\Db;
use Core\TOTP;
use User\Email;
use User\Password;
@ -14,23 +16,18 @@ $password = new Password($u->info);
$email = new Email($u->info);
$status = null;
if ($_POST['oldpsw2']) { // remove psw2
if (password_verify((int)$_POST['oldpsw2'], $u->info['pass2'])) {
$u->info['pass2'] = $password->changeSecond(null)['pass2'];
$status = "<b style='color: darkolivegreen'>Второй пароль выключен.</b><br>";
} else {
$status = "<b style='color: red'>Введен не верный второй пароль!</b><br>";
}
if ($_POST['removetotp']) {
// Удаление ключа ТОТР
$u->info['totp'] = '';
Db::sql('update users set totp = ? where id = ?', [$u->info['totp'], $u->info['id']]);
$status = "<b style='color: darkolivegreen'>Секретный ключ удалён.</b><br>";
}
if ($_POST['num_count']) { //add psw2
$arr = $password->changeSecond((int)$_POST['num_count']);
$status = "<b style='color: red'>Второй пароль: {$arr['pass2']}.<br>
Запомните или запишите, т.к. он не высылается на email и его нельзя как-либо узнать.
Потеряв второй пароль, вы потеряете персонажа!<br>
Этот пароль выслан на ваш email.<br>
</b><br>";
$u->info['pass2'] = $arr['hash'];
if ($_POST['newtotp']) {
// Создание ключа ТОТР
$u->info['totp'] = TOTP::otpSecret($u->info['id']);
Db::sql('update users set totp = ? where id = ?', [$u->info['totp'], $u->info['id']]);
$status = "<b style='color: darkolivegreen'>Секретный ключ создан.</b><br>";
}
if (
@ -66,7 +63,7 @@ if (
}
?>
<form action="main.php?security" method="post" id="security"></form>
<form action="/main.php?security" method="post" id="security"></form>
<div>
<h3>Настройки безопасности</h3>
@ -180,41 +177,18 @@ if (
</TABLE>
</FIELDSET>
<FIELDSET>
<LEGEND><B> Второй уровень защиты </B></LEGEND>
Настоятельно рекомендуем включить второй уровень защиты.<BR>
На компьютере может быть установлен клавиатурный шпион, который записывает все нажатия клавиш, таким
образом,
могут узнать ваш пароль.<BR>
Возможно, в сети компьютеров установлен "сетевой снифер", перехватывающий все интернет пакеты, который легко
покажет все пароли. Чтобы обезопасить себя, вы можете установить своему персонажу второй пароль, который
можно
вводить при помощи мышки (клавиатурным шпионом не перехватить) и который передается на игровой сервер в
зашифрованном виде, не поддающимся расшифровке ("сетевой снифер" не сможет перехватить его).<BR>
<U>Будьте внимательны!</U> Второй пароль отправляется на email один раз,при установке второго уровня защиты!<BR>
<?php
if (!empty($u->info['pass2'])) {
echo "<BR><B>Второй пароль установлен.</B><BR><BR>
Введите второй пароль <INPUT TYPE=password NAME=oldpsw2 size=10 maxlength=8>
<INPUT form='security' TYPE=submit name=changepsw value=\"Выключить второй пароль\" onclick=\"return confirm('Выключить запрос второго пароля при входе в Бойцовский Клуб?')\">";
} else {
?>
Длина пароля:<BR>
<label>
<INPUT form="security" TYPE=radio NAME="num_count" value=4> 4 знака<BR>
</label>
<label>
<INPUT form="security" TYPE=radio NAME="num_count" checked value=6> 6 знаков<BR>
</label>
<label>
<INPUT form="security" TYPE=radio NAME="num_count" value=8> 8 знаков<BR>
</label>
<INPUT form="security" TYPE=submit name=changepsw value="Установить второй пароль"
onclick="return confirm('Система сама придумает вам второй пароль, он будет показан на этой странице, после того, как вы нажмете OK и продублирован на email, указанный при регистрации. Будьте внимательны.\nУстановить второй пароль?')">
<BR>
<?php
}
?>
<LEGEND><B> TOTP </B></LEGEND>
TOTP (Time-based One-Time Password) - это метод двухфакторной аутентификации, который генерирует одноразовый пароль на основе текущего времени.
Устанавливается для повышения безопасности вашего аккаунта, так как помогает защитить его от несанкционированного доступа.<br>
Вы можете использовать TOTP приложения, такие как Google Authenticator или Authy, чтобы генерировать и отображать временные одноразовые пароли на вашем мобильном устройстве.
<br><br>
<U>Будьте внимательны!</U> Секретный ключ генерируется только один раз и не подлежит восстановлению. Его можно только удалить или заменить новым.<br>
<?php if (!empty($u->info['totp'])): ?>
<br><b>Секретный ключ:</b>
<pre>{$u->info['totp']}</pre><br><br>
<input form='security' type='submit' name='removetotp' value='Удалить секретный ключ' disabled><br>
<?php endif; ?>
<input form='security' type='submit' name='newtotp' value='Создать новый секретный ключ' disabled><br>
</FIELDSET>
</div>
</div>