(int)$user['id'], 'login' => $login, 'remember' => (bool)\S::get('remember'), 'started' => time(), ]); if (!\admin\factory\Users::send_twofa_code((int)$user['id'])) { // E-mail nie dotarł — użytkownik podał poprawne dane, więc przepuszczamy \S::delete_session('twofa_pending'); \S::alert('Nie udało się wysłać kodu 2FA — zalogowano bez weryfikacji e-mail.', 'alert-warning'); self::finalize_admin_login($user, $domain, $cookie_name, (bool)\S::get('remember')); header('Location: /admin/articles/view_list/'); 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' => true, '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, "", time() - 86400, "/", $domain); \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'); 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', ]); } } }