Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- //4o
- /**
- * @file AuthService.php
- * @description Contains the core business logic for user authentication.
- * It handles database interactions, password verification, and
- * brute-force protection logic, independent of HTTP context.
- *
- * @version 1.0.0
- * @since 2025-07-25
- * @author Barrac0de
- */
- namespace App\Services;
- use PDO;
- class AuthService
- {
- private PDO $pdo;
- public function __construct()
- {
- require __DIR__ . '/../config.php';
- if (!isset($pdo) || !($pdo instanceof PDO)) {
- http_response_code(500);
- exit('Database connection failed.');
- }
- $this->pdo = $pdo;
- }
- public function processLogin(): void
- {
- if (session_status() === PHP_SESSION_NONE) session_start();
- // Security headers
- header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
- header('X-Frame-Options: DENY');
- header('X-Content-Type-Options: nosniff');
- header('Referrer-Policy: no-referrer');
- header("Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self';");
- // Session timeout check
- $timeout = 3600;
- if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity']) > $timeout) {
- session_unset();
- session_destroy();
- header('Location: ' . BASE_PATH . 'login?timeout=1');
- exit;
- }
- $_SESSION['last_activity'] = time();
- // CSRF check
- $csrfToken = filter_input(INPUT_POST, 'csrf_token', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
- if (empty($_SESSION['csrf_token']) || !hash_equals($_SESSION['csrf_token'], $csrfToken)) {
- $this->bounce('Invalid CSRF token.');
- }
- // Input
- $username = trim((string)filter_input(INPUT_POST, 'username', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
- $password = (string)filter_input(INPUT_POST, 'password', FILTER_UNSAFE_RAW);
- if ($username === '' || $password === '') {
- $this->bounce('Username and password are required.');
- }
- // Fetch user
- $stmt = $this->pdo->prepare('SELECT id, password_hash, failed_login, last_failed_at FROM users WHERE username = :username LIMIT 1');
- $stmt->execute([':username' => $username]);
- $user = $stmt->fetch(PDO::FETCH_ASSOC);
- if (!$user) {
- $this->bounce('Invalid username or password.');
- }
- $failedLogin = (int)$user['failed_login'];
- $lastFailedAt = $user['last_failed_at'] ? strtotime($user['last_failed_at']) : 0;
- $now = time();
- $maxAttempts = 5;
- $lockoutTime = 24 * 60 * 60;
- if ($failedLogin >= $maxAttempts && ($now - $lastFailedAt) < $lockoutTime) {
- $this->bounce('Account locked. Try again later.');
- }
- // Password check
- if (!password_verify($password, (string)$user['password_hash'])) {
- $update = $this->pdo->prepare(
- 'UPDATE users SET failed_login = failed_login + 1, last_failed_at = NOW() WHERE id = :id'
- );
- $update->execute([':id' => $user['id']]);
- $this->bounce('Invalid username or password.');
- }
- // Reset login counter
- $reset = $this->pdo->prepare('UPDATE users SET failed_login = 0, last_failed_at = NULL WHERE id = :id');
- $reset->execute([':id' => $user['id']]);
- // Login success
- session_regenerate_id(true);
- $_SESSION['user_id'] = $user['id'];
- $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
- header('Location: ' . BASE_PATH . 'index');
- exit;
- }
- private function bounce(string $message): void
- {
- $old = trim((string)filter_input(INPUT_POST, 'username', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
- $_SESSION['old_username'] = $old;
- $_SESSION['login_error'] = $message;
- header('Location: ' . BASE_PATH . 'login');
- exit;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment