Dodanie obsługi dwustopniowego uwierzytelniania (2FA) dla użytkowników; wprowadzenie mechanizmu zapamiętywania sesji oraz aktualizacja szablonów i plików konfiguracyjnych.

This commit is contained in:
2025-12-16 23:17:00 +01:00
parent 32aa4a3544
commit 6af91475ae
12 changed files with 525 additions and 58 deletions

View File

@@ -3,33 +3,183 @@ namespace admin;
class Site
{
// define APP_SECRET_KEY
const APP_SECRET_KEY = 'c3cb2537d25c0efc9e573d059d79c3b8';
static public function finalize_admin_login( array $user, string $domain, string $cookie_name, bool $remember = false ) {
\S::set_session( 'user', $user );
\S::delete_session( 'twofa_pending' );
if ( $remember ) {
$payloadArr = [
'login' => $user['login'],
'ts' => time()
];
$json = json_encode($payloadArr, JSON_UNESCAPED_SLASHES);
$sig = hash_hmac('sha256', $json, self::APP_SECRET_KEY);
$payload = base64_encode($json . '.' . $sig);
setcookie( $cookie_name, $payload, [
'expires' => time() + (86400 * 14),
'path' => '/',
'domain' => $domain,
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
}
}
public static function special_actions()
{
$sa = \S::get( 's-action' );
$sa = \S::get('s-action');
$domain = preg_replace('/^www\./', '', $_SERVER['SERVER_NAME']);
$cookie_name = 'admin_remember_' . str_replace( '.', '-', $domain );
switch ( $sa )
switch ($sa)
{
case 'user-logon':
{
$login = \S::get('login');
$pass = \S::get('password');
$result = \admin\factory\Users::logon( \S::get( 'login' ), \S::get( 'password' ) );
$result = \admin\factory\Users::logon($login, $pass);
if ( $result == 1 )
\S::set_session( 'user', \admin\factory\Users::details( \S::get( 'login' ) ) );
{
$user = \admin\factory\Users::details($login);
if ( $user['twofa_enabled'] == 1 )
{
\S::set_session( 'twofa_pending', [
'uid' => (int)$user['id'],
'login' => $login,
'remember' => (bool)\S::get('remember'),
'started' => time(),
] );
if ( !\admin\factory\Users::send_twofa_code( (int)$user['id'] ) )
{
\S::alert('Nie udało się wysłać kodu 2FA. Spróbuj ponownie.');
\S::delete_session('twofa_pending');
header('Location: /admin/');
exit;
}
header('Location: /admin/user/twofa/');
exit;
}
else
{
$user = \admin\factory\Users::details($login);
self::finalize_admin_login(
$user,
$domain,
$cookie_name,
(bool)\S::get('remember')
);
header('Location: /admin/articles/view_list/');
exit;
}
}
else
{
if ( $result == -1 )
\S::alert( 'Z powodu nieudanych 5 prób logowania Twoje konto zostało zablokowane.' );
if ($result == -1)
{
\S::alert('Z powodu 5 nieudanych prób Twoje konto zostało zablokowane.');
}
else
\S::alert( 'Podane hasło jest nieprawidłowe, lub brak użytkownika o podanym loginie.' );
{
\S::alert('Podane hasło jest nieprawidłowe lub użytkownik nie istnieje.');
}
header('Location: /admin/');
exit;
}
header( 'Location: /admin/dashboard/main_view/' );
}
break;
case 'user-2fa-verify':
{
$pending = \S::get_session('twofa_pending');
if ( !$pending || empty( $pending['uid'] ) ) {
\S::alert('Sesja 2FA wygasła. Zaloguj się ponownie.');
header('Location: /admin/');
exit;
}
$code = trim((string)\S::get('twofa'));
if (!preg_match('/^\d{6}$/', $code))
{
\S::alert('Nieprawidłowy format kodu.');
header('Location: /admin/user/twofa/');
exit;
}
$ok = \admin\factory\Users::verify_twofa_code((int)$pending['uid'], $code);
if (!$ok)
{
\S::alert('Błędny lub wygasły kod.');
header('Location: /admin/user/twofa/');
exit;
}
// 2FA OK — finalna sesja
$user = \admin\factory\Users::details($pending['login']);
self::finalize_admin_login(
$user,
$domain,
$cookie_name,
$pending['remember'] ? true : false
);
header('Location: /admin/articles/view_list/');
exit;
}
break;
case 'user-2fa-resend':
{
$pending = \S::get_session('twofa_pending');
if (!$pending || empty($pending['uid']))
{
\S::alert('Sesja 2FA wygasła. Zaloguj się ponownie.');
header('Location: /admin/');
exit;
}
if (!\admin\factory\Users::send_twofa_code((int)$pending['uid'], true))
{
\S::alert('Kod można wysłać ponownie po krótkiej przerwie.');
}
else
{
\S::alert('Nowy kod został wysłany.');
}
header('Location: /admin/user/twofa/');
exit;
}
break;
case 'user-logout':
{
setcookie($cookie_name, "", [
'expires' => time() - 86400,
'path' => '/',
'domain' => $domain,
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
\S::delete_session('twofa_pending');
session_destroy();
header( 'Location: /admin/' );
header('Location: /admin/');
exit;
}
break;
}
}