242 lines
6.7 KiB
PHP
242 lines
6.7 KiB
PHP
<?php
|
||
|
||
namespace admin;
|
||
|
||
class Site
|
||
{
|
||
// define APP_SECRET_KEY
|
||
const APP_SECRET_KEY = 'c3cb2537d25c0efc9e573d059d79c3b8';
|
||
|
||
private static function cookie_scope(): array
|
||
{
|
||
$host = $_SERVER['HTTP_HOST'] ?? ( $_SERVER['SERVER_NAME'] ?? '' );
|
||
$host = strtolower( preg_replace( '/:\d+$/', '', $host ) );
|
||
$host = preg_replace( '/^www\./', '', $host );
|
||
|
||
$isIp = filter_var( $host, FILTER_VALIDATE_IP ) !== false;
|
||
$https = !empty( $_SERVER['HTTPS'] ) && strtolower( (string)$_SERVER['HTTPS'] ) !== 'off';
|
||
|
||
return [
|
||
'domain' => $isIp || $host === 'localhost' ? '' : $host,
|
||
'name' => str_replace( '.', '-', $host ),
|
||
'secure' => $https,
|
||
];
|
||
}
|
||
|
||
public static function special_actions()
|
||
{
|
||
$sa = \S::get('s-action');
|
||
$scope = self::cookie_scope();
|
||
$domain = $scope['domain'];
|
||
$cookie_name = $scope['name'];
|
||
|
||
switch ($sa)
|
||
{
|
||
case 'user-logon':
|
||
{
|
||
$login = \S::get('login');
|
||
$pass = \S::get('password');
|
||
|
||
$result = \admin\factory\Users::logon($login, $pass);
|
||
|
||
if ($result == 1)
|
||
{
|
||
$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 5 nieudanych prób Twoje konto zostało zablokowane.');
|
||
}
|
||
else
|
||
{
|
||
\S::alert('Podane hasło jest nieprawidłowe lub użytkownik nie istnieje.');
|
||
}
|
||
header('Location: /admin/');
|
||
exit;
|
||
}
|
||
}
|
||
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']);
|
||
\S::set_session('user', $user);
|
||
\S::delete_session('twofa_pending');
|
||
|
||
// Remember me – BEZPIECZNY podpis HMAC:
|
||
if (!empty($pending['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' => $scope['secure'],
|
||
'httponly' => true,
|
||
'samesite' => 'Lax',
|
||
]);
|
||
}
|
||
|
||
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' => $scope['secure'],
|
||
'httponly' => true,
|
||
'samesite' => 'Lax',
|
||
]);
|
||
\S::delete_session('twofa_pending');
|
||
session_destroy();
|
||
header('Location: /admin/');
|
||
exit;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
public static function route()
|
||
{
|
||
$_SESSION['admin'] = true;
|
||
|
||
$class = '\admin\controls\\';
|
||
|
||
$results = explode('_', \S::get('module'));
|
||
if (is_array($results)) foreach ($results as $row)
|
||
$class .= ucfirst($row);
|
||
|
||
$action = \S::get('action');
|
||
|
||
if (class_exists($class) and method_exists(new $class, $action))
|
||
return call_user_func_array(array($class, $action), array());
|
||
else
|
||
{
|
||
\S::alert('Nieprawidłowy adres url.');
|
||
return false;
|
||
}
|
||
}
|
||
|
||
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');
|
||
$scope = self::cookie_scope();
|
||
|
||
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' => $scope['secure'],
|
||
'httponly' => true,
|
||
'samesite' => 'Lax',
|
||
]);
|
||
}
|
||
}
|
||
}
|