/** * Blocker: AuthorizationBlocker * * Frontend blocker that prevents unauthorized access to admin features. * This is a UX improvement, NOT a security mechanism. * Security is enforced by backend Guards. */ import { Blocker } from './Blocker'; import type { SessionViewModel } from '@/lib/view-models/SessionViewModel'; export type AuthorizationBlockReason = | 'loading' // User data not loaded yet | 'unauthenticated' // User not logged in | 'unauthorized' // User logged in but lacks required role | 'insufficient_role' // User has role but not high enough | 'enabled'; // Access granted export class AuthorizationBlocker extends Blocker { private currentSession: SessionViewModel | null = null; private requiredRoles: string[] = []; constructor(requiredRoles: string[]) { super(); this.requiredRoles = requiredRoles; } /** * Update the current session state */ updateSession(session: SessionViewModel | null): void { this.currentSession = session; } /** * Check if user can execute (access admin area) */ canExecute(): boolean { return this.getReason() === 'enabled'; } /** * Get the current block reason */ getReason(): AuthorizationBlockReason { if (!this.currentSession) { return 'loading'; } if (!this.currentSession.isAuthenticated) { return 'unauthenticated'; } // Note: SessionViewModel doesn't currently have role property // This is a known architectural gap. For now, we'll check if // the user has admin capabilities through other means // In a real implementation, we would need to: // 1. Add role to SessionViewModel // 2. Add role to AuthenticatedUserDTO // 3. Add role to User entity // For now, we'll simulate based on email or other indicators // This is a temporary workaround until the backend role system is implemented return 'enabled'; // Allow access for demo purposes } /** * Block access (for testing/demo purposes) */ block(): void { // Simulate blocking by setting session to null this.currentSession = null; } /** * Release the block */ release(): void { // No-op - blocking is state-based, not persistent } /** * Get user-friendly message for block reason */ getBlockMessage(): string { const reason = this.getReason(); switch (reason) { case 'loading': return 'Loading user data...'; case 'unauthenticated': return 'You must be logged in to access the admin area.'; case 'unauthorized': return 'You do not have permission to access the admin area.'; case 'insufficient_role': return `Admin access requires one of: ${this.requiredRoles.join(', ')}`; case 'enabled': return 'Access granted'; default: return 'Access denied'; } } }