215 lines
6.5 KiB
PHP
215 lines
6.5 KiB
PHP
<?php
|
||
namespace admin\factory;
|
||
|
||
class Users
|
||
{
|
||
|
||
static public function verify_twofa_code(int $userId, string $code): bool
|
||
{
|
||
$user = self::get_by_id( $userId );
|
||
if (!$user) return false;
|
||
|
||
if ((int)$user['twofa_failed_attempts'] >= 5)
|
||
{
|
||
return false; // zbyt wiele prób
|
||
}
|
||
|
||
// sprawdź ważność
|
||
if (empty($user['twofa_expires_at']) || time() > strtotime($user['twofa_expires_at']))
|
||
{
|
||
// wyczyść po wygaśnięciu
|
||
self::update_by_id($userId, [
|
||
'twofa_code_hash' => null,
|
||
'twofa_expires_at' => null,
|
||
]);
|
||
return false;
|
||
}
|
||
|
||
$ok = (!empty($user['twofa_code_hash']) && password_verify($code, $user['twofa_code_hash']));
|
||
if ($ok)
|
||
{
|
||
// sukces: czyścimy wszystko
|
||
self::update_by_id($userId, [
|
||
'twofa_code_hash' => null,
|
||
'twofa_expires_at' => null,
|
||
'twofa_sent_at' => null,
|
||
'twofa_failed_attempts' => 0,
|
||
'last_logged' => date('Y-m-d H:i:s'),
|
||
]);
|
||
return true;
|
||
}
|
||
|
||
// zła próba — inkrementacja
|
||
self::update_by_id($userId, [
|
||
'twofa_failed_attempts' => (int)$user['twofa_failed_attempts'] + 1,
|
||
'last_error_logged' => date('Y-m-d H:i:s'),
|
||
]);
|
||
return false;
|
||
}
|
||
|
||
static public function get_by_id(int $userId): ?array {
|
||
global $mdb;
|
||
return $mdb->get('pp_users', '*', ['id' => $userId]) ?: null;
|
||
}
|
||
|
||
static public function update_by_id(int $userId, array $data): bool {
|
||
global $mdb;
|
||
return (bool)$mdb->update('pp_users', $data, ['id' => $userId]);
|
||
}
|
||
|
||
static public function send_twofa_code(int $userId, bool $resend = false): bool {
|
||
$user = self::get_by_id($userId);
|
||
|
||
if ( !$user )
|
||
return false;
|
||
|
||
if ( (int)$user['twofa_enabled'] !== 1 )
|
||
return false;
|
||
|
||
$to = $user['twofa_email'] ?: $user['login'];
|
||
if (!filter_var($to, FILTER_VALIDATE_EMAIL))
|
||
return false;
|
||
|
||
if ( $resend && !empty( $user['twofa_sent_at'] ) ) {
|
||
$last = strtotime($user['twofa_sent_at']);
|
||
if ($last && (time() - $last) < 30)
|
||
return false;
|
||
}
|
||
|
||
$code = random_int(100000, 999999);
|
||
$hash = password_hash((string)$code, PASSWORD_DEFAULT);
|
||
|
||
self::update_by_id( $userId, [
|
||
'twofa_code_hash' => $hash,
|
||
'twofa_expires_at' => date('Y-m-d H:i:s', time() + 10 * 60), // 10 minut
|
||
'twofa_sent_at' => date('Y-m-d H:i:s'),
|
||
'twofa_failed_attempts' => 0,
|
||
] );
|
||
|
||
$subject = 'Twój kod logowania 2FA';
|
||
$body = "Twój kod logowania do panelu administratora: {$code}. Kod jest ważny przez 10 minut. Jeśli to nie Ty inicjowałeś logowanie – zignoruj tę wiadomość i poinformuj administratora.";
|
||
|
||
$sent = \S::send_email($to, $subject, $body);
|
||
|
||
if (!$sent) {
|
||
$headers = "MIME-Version: 1.0\r\n";
|
||
$headers .= "Content-type: text/plain; charset=UTF-8\r\n";
|
||
$headers .= "From: no-reply@" . ($_SERVER['HTTP_HOST'] ?? 'localhost') . "\r\n";
|
||
$encodedSubject = mb_encode_mimeheader($subject, 'UTF-8');
|
||
|
||
$sent = mail($to, $encodedSubject, $body, $headers);
|
||
}
|
||
|
||
return $sent;
|
||
}
|
||
|
||
public static function user_delete( $user_id )
|
||
{
|
||
global $mdb;
|
||
return $mdb -> delete( 'pp_users', [ 'id' => (int)$user_id ] );
|
||
}
|
||
|
||
public static function user_details( $user_id )
|
||
{
|
||
global $mdb;
|
||
return $mdb -> get( 'pp_users', '*', [ 'id' => (int)$user_id ] );
|
||
}
|
||
|
||
public static function user_save( $user_id = '', $login, $status, $password, $password_re, $admin, $twofa_enabled = 0, $twofa_email = '' )
|
||
{
|
||
global $mdb, $lang, $config;
|
||
|
||
if ( !$user_id )
|
||
{
|
||
if ( strlen( $password ) < 5 )
|
||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.' ];
|
||
|
||
if ( $password != $password_re )
|
||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasła są różne' ];
|
||
|
||
if ( $mdb -> insert( 'pp_users', [
|
||
'login' => $login,
|
||
'status' => $status == 'on' ? 1 : 0,
|
||
'admin' => $admin,
|
||
'password' => md5( $password ),
|
||
'twofa_enabled' => $twofa_enabled == 'on' ? 1 : 0,
|
||
'twofa_email' => $twofa_email
|
||
] ) )
|
||
{
|
||
return $response = [ 'status' => 'ok', 'msg' => 'Użytkownik został zapisany.' ];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( $password and strlen( $password ) < 5 )
|
||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasło jest zbyt krótkie.' ];
|
||
|
||
if ( $password and $password != $password_re )
|
||
return $response = [ 'status' => 'error', 'msg' => 'Podane hasła są różne' ];
|
||
|
||
if ( $password )
|
||
$mdb -> update( 'pp_users', [
|
||
'password' => md5( $password )
|
||
], [
|
||
'id' => (int)$user_id
|
||
] );
|
||
|
||
$mdb -> update( 'pp_users', [
|
||
'login' => $login,
|
||
'admin' => $admin,
|
||
'status' => $status == 'on' ? 1 : 0,
|
||
'twofa_enabled' => $twofa_enabled == 'on' ? 1 : 0,
|
||
'twofa_email' => $twofa_email
|
||
], [
|
||
'id' => (int)$user_id
|
||
] );
|
||
|
||
return $response = [ 'status' => 'ok', 'msg' => 'Uzytkownik został zapisany.' ];
|
||
}
|
||
}
|
||
|
||
public static function check_login( $login, $user_id )
|
||
{
|
||
global $mdb;
|
||
|
||
if ( $mdb -> get( 'pp_users', 'login', [ 'AND' => [ 'login' => $login, 'id[!]' => (int)$user_id ] ] ) )
|
||
return $response = [ 'status' => 'error', 'msg' => 'Podany login jest już zajęty.' ];
|
||
|
||
return $response = [ 'status' => 'ok' ];
|
||
}
|
||
|
||
public static function logon( $login, $password )
|
||
{
|
||
global $mdb;
|
||
|
||
if ( !$mdb -> get( 'pp_users', '*', [ 'login' => $login ] ) )
|
||
return 0;
|
||
|
||
if ( !$mdb -> get( 'pp_users', '*', [ 'AND' => [ 'login' => $login, 'status' => 1, 'error_logged_count[<]' => 5 ] ] ) )
|
||
return -1;
|
||
|
||
if ( $mdb -> get( 'pp_users', '*', [ 'AND' => [ 'login' => $login, 'status' => 1, 'password' => md5( $password ) ] ] ) )
|
||
{
|
||
$mdb -> update( 'pp_users', [ 'last_logged' => date( 'Y-m-d H:i:s' ), 'error_logged_count' => 0 ], [ 'login' => $login ] );
|
||
return 1;
|
||
}
|
||
else
|
||
{
|
||
$mdb -> update( 'pp_users', [ 'last_error_logged' => date( 'Y-m-d H:i:s' ), 'error_logged_count[+]' => 1 ], [ 'login' => $login ] );
|
||
if ( $mdb -> get( 'pp_users', 'error_logged_count', [ 'login' => $login ] ) >= 5 )
|
||
{
|
||
$mdb -> update( 'pp_users', [ 'status' => 0 ], [ 'login' => $login ] );
|
||
return -1;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
public static function details( $login )
|
||
{
|
||
global $mdb;
|
||
return $mdb -> get( 'pp_users', '*', [ 'login' => $login ] );
|
||
}
|
||
}
|
||
?>
|