import { AuthenticationState } from '../../domain/value-objects/AuthenticationState'; import { Result } from '../../shared/result/Result'; import type { IAuthenticationService } from '../ports/IAuthenticationService'; import { SessionLifetime } from '../../domain/value-objects/SessionLifetime'; /** * Port for optional server-side session validation. */ export interface ISessionValidator { validateSession(): Promise>; } /** * Use case for checking if the user has a valid iRacing session. * * This validates the session before automation starts, allowing * the system to prompt for re-authentication if needed. * * Implements hybrid validation strategy: * - File-based validation (fast, always executed) * - Optional server-side validation (slow, requires network) */ export class CheckAuthenticationUseCase { constructor( private readonly authService: IAuthenticationService, private readonly sessionValidator?: ISessionValidator ) {} /** * Execute the authentication check. * * @param options Optional configuration for validation * @returns Result containing the current AuthenticationState */ async execute(options?: { requireServerValidation?: boolean; verifyPageContent?: boolean; }): Promise> { // Step 1: File-based validation (fast) const fileResult = await this.authService.checkSession(); if (fileResult.isErr()) { return fileResult; } const fileState = fileResult.unwrap(); // Step 2: Check session expiry if authenticated if (fileState === AuthenticationState.AUTHENTICATED) { const expiryResult = await this.authService.getSessionExpiry(); if (expiryResult.isErr()) { // Don't fail completely if we can't get expiry, use file-based state return Result.ok(fileState); } const expiry = expiryResult.unwrap(); if (expiry !== null) { try { const sessionLifetime = new SessionLifetime(expiry); if (sessionLifetime.isExpired()) { return Result.ok(AuthenticationState.EXPIRED); } } catch { // Invalid expiry date, treat as expired for safety return Result.ok(AuthenticationState.EXPIRED); } } } // Step 3: Optional page content verification if (options?.verifyPageContent && fileState === AuthenticationState.AUTHENTICATED) { const pageResult = await this.authService.verifyPageAuthentication(); if (pageResult.isOk()) { const browserState = pageResult.unwrap(); // If cookies valid but page shows login UI, session is expired if (!browserState.isFullyAuthenticated()) { return Result.ok(AuthenticationState.EXPIRED); } } // Don't block on page verification errors, continue with file-based state } // Step 4: Optional server-side validation if (this.sessionValidator && fileState === AuthenticationState.AUTHENTICATED) { const serverResult = await this.sessionValidator.validateSession(); // Don't block on server validation errors if (serverResult.isOk()) { const isValid = serverResult.unwrap(); if (!isValid) { return Result.ok(AuthenticationState.EXPIRED); } } } return Result.ok(fileState); } }