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:
@@ -85,5 +85,47 @@ $user = \S::get_session( 'user', true );
|
||||
\admin\Site::update();
|
||||
\admin\Site::special_actions();
|
||||
|
||||
$domain = preg_replace( '/^www\./', '', $_SERVER['SERVER_NAME'] );
|
||||
$cookie_name = 'admin_remember_' . str_replace( '.', '-', $domain );
|
||||
|
||||
if ( isset( $_COOKIE[$cookie_name] ) && !isset( $_SESSION['user'] ) )
|
||||
{
|
||||
$payload = base64_decode($_COOKIE[$cookie_name]);
|
||||
if ($payload !== false && strpos($payload, '.') !== false)
|
||||
{
|
||||
list($json, $sig) = explode('.', $payload, 2);
|
||||
$expected_sig = hash_hmac('sha256', $json, \admin\Site::APP_SECRET_KEY);
|
||||
|
||||
if (hash_equals($expected_sig, $sig))
|
||||
{
|
||||
$data = json_decode($json, true);
|
||||
if ($data && isset($data['login']) && isset($data['ts']))
|
||||
{
|
||||
// Sprawdź czy cookie nie wygasło (14 dni)
|
||||
if ((time() - $data['ts']) < (86400 * 14))
|
||||
{
|
||||
$user_data = $mdb->get('pp_users', '*', ['AND' => ['login' => $data['login'], 'status' => 1]]);
|
||||
if ($user_data)
|
||||
{
|
||||
\S::set_session('user', \admin\factory\Users::details($data['login']));
|
||||
$redirect = $_SERVER['REQUEST_URI'] ?: '/admin/articles/view_list/';
|
||||
header('Location: ' . $redirect);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Jeśli coś poszło nie tak, usuń nieprawidłowe cookie
|
||||
setcookie($cookie_name, '', [
|
||||
'expires' => time() - 86400,
|
||||
'path' => '/',
|
||||
'domain' => $domain,
|
||||
'secure' => true,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
}
|
||||
|
||||
echo \admin\view\Page::show();
|
||||
?>
|
||||
20
admin/layout/.htaccess
Normal file
20
admin/layout/.htaccess
Normal file
@@ -0,0 +1,20 @@
|
||||
# Wyłącz listowanie
|
||||
Options -Indexes
|
||||
|
||||
# Domyślnie blokujemy wszystko…
|
||||
Require all denied
|
||||
|
||||
# …a dopiero potem pozwalamy na pliki statyczne
|
||||
<FilesMatch "\.(css|js|map|mjs|png|jpe?g|gif|svgz?|webp|ico|woff2?|woff|ttf|eot)$">
|
||||
Require all granted
|
||||
</FilesMatch>
|
||||
|
||||
# Twardo blokuj cokolwiek, co mogłoby się wykonać
|
||||
<FilesMatch "\.(php|phtml|php[0-9]?|phar|pht|cgi|pl|py|sh)$">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
# Nie serwuj plików ukrytych (.env itp.)
|
||||
<FilesMatch "^\.(.*)$">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
20
admin/templates/.htaccess
Normal file
20
admin/templates/.htaccess
Normal file
@@ -0,0 +1,20 @@
|
||||
# Wyłącz listowanie
|
||||
Options -Indexes
|
||||
|
||||
# Domyślnie blokujemy wszystko…
|
||||
Require all denied
|
||||
|
||||
# …a dopiero potem pozwalamy na pliki statyczne
|
||||
<FilesMatch "\.(css|js|map|mjs|png|jpe?g|gif|svgz?|webp|ico|woff2?|woff|ttf|eot)$">
|
||||
Require all granted
|
||||
</FilesMatch>
|
||||
|
||||
# Twardo blokuj cokolwiek, co mogłoby się wykonać
|
||||
<FilesMatch "\.(php|phtml|php[0-9]?|phar|pht|cgi|pl|py|sh)$">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
|
||||
# Nie serwuj plików ukrytych (.env itp.)
|
||||
<FilesMatch "^\.(.*)$">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
@@ -63,9 +63,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sumbit">
|
||||
<button class="btn">Zaloguj się</button>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col col-sm-12" style="align-items: center; display: flex;">
|
||||
<input id="remember" type="checkbox" name="remember" value="1">
|
||||
<label class="remember" style="margin-bottom: 0; margin-left: 5px;"> Pamiętaj mnie 14 dni</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sumbit">
|
||||
<button class="btn">Zaloguj się</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="copyright">
|
||||
<a href="https://www.project-pro.pl/"> © <?= date( 'Y' );?> Project-Pro</a>
|
||||
|
||||
60
admin/templates/site/unlogged.php
Normal file
60
admin/templates/site/unlogged.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>shopPro</title>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="author" content="www.project-pro.pl - internetowe rozwiązania dla biznesu">
|
||||
<link rel="stylesheet" type="text/css" href="/libraries/bootstrap-4.5.2-dist/css/bootstrap.css">
|
||||
<link rel="stylesheet" type="text/css" href="/libraries/font-awesome-4.7.0/css/font-awesome.css">
|
||||
<link rel="stylesheet" href="/admin/layout/style-css/style.css">
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script type="text/javascript" src="/libraries/bootstrap-4.5.2-dist/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="/libraries/bootstrap-4.5.2-dist/js/bootstrap.bundle.min.js"></script>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,600;0,700;0,800;1,300;1,400;1,600;1,700;1,800&display=swap" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div id="main">
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-md-6 col-lg-4 unlogged-panel">
|
||||
<div class="login-panel">
|
||||
<div class="login-panel-content">
|
||||
<div class="login-shoppro">
|
||||
shop<b>Pro</b>
|
||||
</div>
|
||||
<div class="title">
|
||||
Witaj ponownie!
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
Zaloguj się do panelu administratora <b>shopPro</b>.
|
||||
</div>
|
||||
<?
|
||||
if ( $alert = \S::get_session( 'alert' ) ):
|
||||
\S::alert( false );
|
||||
?>
|
||||
<div class="alert alert-danger alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="icon fa fa-ban "></i><?= $alert;?>
|
||||
</div>
|
||||
<? endif;
|
||||
?>
|
||||
<?= $this -> content; ?>
|
||||
<div class="copyright">
|
||||
<a href="https://www.project-pro.pl/"> © <?= date( 'Y' );?> Project-Pro</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4 col-md-6 col-lg-8 unlogged-bg">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="home">
|
||||
<a href="/"><img src="/admin/layout/images/home.svg" alt="HOME"></a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
18
admin/templates/users/user-2fa.php
Normal file
18
admin/templates/users/user-2fa.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<form method="POST" action="/admin/" class="form-horizontal" rol="form">
|
||||
<input type="hidden" name="s-action" value="user-2fa-verify">
|
||||
<div class="form-group row">
|
||||
<label class="col col-sm-4 control-label" for="login">Kod z e-maila:</label>
|
||||
<div class="col col-sm-8">
|
||||
<input type="text" name="twofa" id="twofa" class="form-control" inputmode="numeric" pattern="\d{6}" maxlength="6" autocomplete="one-time-code" required>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<div class="col col-sm-12">
|
||||
<button class="btn btn-primary btn-block">Potwierdź</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form method="POST" action="/admin/" style="margin-top:10px">
|
||||
<input type="hidden" name="s-action" value="user-2fa-resend">
|
||||
<button class="btn btn-danger">Wyślij kod ponownie</button>
|
||||
</form>
|
||||
@@ -18,7 +18,7 @@ $grid -> fields = [
|
||||
'type' => 'hidden',
|
||||
'value' => '1'
|
||||
],
|
||||
[
|
||||
[
|
||||
'name' => 'Login',
|
||||
'db' => 'login',
|
||||
'type' => 'text',
|
||||
@@ -30,8 +30,17 @@ $grid -> fields = [
|
||||
'db' => 'status',
|
||||
'type' => 'input_switch',
|
||||
'checked' => $this -> user['status'] ? true : false
|
||||
],
|
||||
[
|
||||
], [
|
||||
'db' => 'twofa_enabled',
|
||||
'name' => 'Dwustopniowe uwierzytelnianie (2FA)',
|
||||
'type' => 'input_switch',
|
||||
'checked' => $this -> user['twofa_enabled'] ? true : false,
|
||||
], [
|
||||
'db' => 'twofa_email',
|
||||
'name' => 'E-mail do 2FA',
|
||||
'type' => 'text',
|
||||
'value' => $this -> user['twofa_email'],
|
||||
], [
|
||||
'name' => 'Hasło',
|
||||
'db' => 'password',
|
||||
'type' => 'text',
|
||||
@@ -44,9 +53,9 @@ $grid -> fields = [
|
||||
'params' => [ 'class' => $password_param, 'min' => 5, 'equal' => 'password', 'error_txt' => 'Podane hasła są różne' ]
|
||||
]
|
||||
];
|
||||
$grid -> actions = [
|
||||
'save' => [ 'url' => '/admin/users/user_save/', 'back_url' => '/admin/users/view_list/' ],
|
||||
'cancel' => [ 'url' => '/admin/users/view_list/' ]
|
||||
$grid -> actions = [
|
||||
'save' => [ 'url' => '/admin/users/user_save/', 'back_url' => '/admin/users/view_list/' ],
|
||||
'cancel' => [ 'url' => '/admin/users/view_list/' ]
|
||||
];
|
||||
echo $grid -> draw();
|
||||
?>
|
||||
@@ -55,11 +64,11 @@ echo $grid -> draw();
|
||||
{
|
||||
disable_menu();
|
||||
});
|
||||
|
||||
function check_login()
|
||||
|
||||
function check_login()
|
||||
{
|
||||
var response = null;
|
||||
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
cache: false,
|
||||
@@ -77,5 +86,5 @@ echo $grid -> draw();
|
||||
}
|
||||
});
|
||||
return response;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user