widimulcing

AuthService.php

Jul 29th, 2025
242
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 3.57 KB | None | 0 0
  1. <?php
  2. // Gemini
  3. /**
  4.  * @file        AuthService.php
  5.  * @description Contains the core business logic for user authentication.
  6.  * It handles database interactions, password verification, and
  7.  * brute-force protection logic, independent of HTTP context.
  8.  *
  9.  * @version     1.0.0
  10.  * @since       2025-07-25
  11.  * @author      Barrac0de
  12.  */
  13. declare(strict_types=1);
  14.  
  15. namespace App\Auth;
  16.  
  17. use PDO;
  18.  
  19. class AuthService
  20. {
  21.     private PDO $pdo;
  22.     private const MAX_ATTEMPTS = 5;
  23.     private const LOCK_TIME = 24 * 60 * 60; // 24 hours in seconds
  24.  
  25.     public function __construct(PDO $pdo)
  26.     {
  27.         $this->pdo = $pdo;
  28.     }
  29.  
  30.     /**
  31.      * Attempts to log a user in with the given credentials.
  32.      *
  33.      * @param string $username The user's username.
  34.      * @param string $password The user's password.
  35.      * @return array An array with 'success' (bool) and 'message' or 'user_id'.
  36.      */
  37.     public function attemptLogin(string $username, string $password): array
  38.     {
  39.         $stmt = $this->pdo->prepare(
  40.             'SELECT id, password_hash, failed_login, last_failed_at FROM users WHERE username = :username LIMIT 1'
  41.         );
  42.         $stmt->execute([':username' => $username]);
  43.         $user = $stmt->fetch(PDO::FETCH_ASSOC);
  44.  
  45.         if (!$user) {
  46.             // Use a generic message to prevent username enumeration
  47.             return ['success' => false, 'message' => 'Invalid username or password.'];
  48.         }
  49.  
  50.         // Brute-force protection check
  51.         $failedLogin = (int)$user['failed_login'];
  52.         $lastFailedAt = $user['last_failed_at'] ? strtotime($user['last_failed_at']) : 0;
  53.  
  54.         if ($failedLogin >= self::MAX_ATTEMPTS && (time() - $lastFailedAt) < self::LOCK_TIME) {
  55.             return ['success' => false, 'message' => 'Account locked. Try again later.'];
  56.         }
  57.  
  58.         // Verify password
  59.         if (!password_verify($password, (string)$user['password_hash'])) {
  60.             $this->incrementFailedAttempts($user['id']);
  61.             return ['success' => false, 'message' => 'Invalid username or password.'];
  62.         }
  63.  
  64.         // Login is successful
  65.         $this->resetFailedAttempts($user['id']);
  66.         return ['success' => true, 'user_id' => (int)$user['id']];
  67.     }
  68.  
  69.     /**
  70.      * Increments the failed login counter for a user.
  71.      * @param int $userId The ID of the user.
  72.      */
  73.     private function incrementFailedAttempts(int $userId): void
  74.     {
  75.         $stmt = $this->pdo->prepare(
  76.             'UPDATE users SET failed_login = failed_login + 1, last_failed_at = NOW() WHERE id = :id'
  77.         );
  78.         $stmt->execute([':id' => $userId]);
  79.     }
  80.  
  81.     /**
  82.      * Resets the failed login counter for a user.
  83.      * @param int $userId The ID of the user.
  84.      */
  85.     private function resetFailedAttempts(int $userId): void
  86.     {
  87.         $stmt = $this->pdo->prepare(
  88.             'UPDATE users SET failed_login = 0, last_failed_at = NULL WHERE id = :id'
  89.         );
  90.         $stmt->execute([':id' => $userId]);
  91.     }
  92.  
  93.     /**
  94.      * Checks if the user session has timed out.
  95.      */
  96.     public static function checkSessionTimeout(): void
  97.     {
  98.         $timeout = 3600; // 1 hour
  99.         if (isset($_SESSION['last_activity']) && (time() - $_SESSION['last_activity']) > $timeout) {
  100.             session_unset();
  101.             session_destroy();
  102.             header('Location: ' . BASE_PATH . 'login?timeout=1');
  103.             exit;
  104.         }
  105.         // Update last activity time on each request
  106.         if(isset($_SESSION['user_id'])) {
  107.             $_SESSION['last_activity'] = time();
  108.         }
  109.     }
  110. }
  111.  
Advertisement
Add Comment
Please, Sign In to add comment