Files
gridpilot.gg/apps/website/lib/auth/RouteGuard.ts
2026-01-03 02:42:47 +01:00

57 lines
1.9 KiB
TypeScript

import { redirect } from 'next/navigation';
import { PathnameInterpreter } from './PathnameInterpreter';
import { RouteAccessPolicy } from './RouteAccessPolicy';
import { SessionGateway } from '../gateways/SessionGateway';
import { AuthRedirectBuilder } from './AuthRedirectBuilder';
import type { AuthSessionDTO } from '../types/generated/AuthSessionDTO';
export class RouteGuard {
constructor(
private readonly interpreter: PathnameInterpreter,
private readonly policy: RouteAccessPolicy,
private readonly gateway: SessionGateway,
private readonly builder: AuthRedirectBuilder
) {}
async enforce({ pathname }: { pathname: string }): Promise<void> {
// Step 1: Interpret the pathname
const { logicalPathname } = this.interpreter.interpret(pathname);
// Step 2: Check if public non-auth page
if (this.policy.isPublic(logicalPathname) && !this.policy.isAuthPage(logicalPathname)) {
return; // Allow access
}
// Step 3: Handle auth pages
if (this.policy.isAuthPage(logicalPathname)) {
const session = await this.gateway.getSession();
if (session) {
// User is logged in, redirect away from auth page
const redirectPath = this.builder.awayFromAuthPage({ session, currentPathname: pathname });
redirect(redirectPath);
}
// No session, allow access to auth page
return;
}
// Step 4: Handle protected pages
const session = await this.gateway.getSession();
// No session, redirect to login
if (!session) {
const loginPath = this.builder.toLogin({ currentPathname: pathname });
redirect(loginPath);
}
// Check required roles
const reqRoles = this.policy.requiredRoles(logicalPathname);
if (reqRoles && session.user?.role && !reqRoles.includes(session.user.role)) {
const loginPath = this.builder.toLogin({ currentPathname: pathname });
redirect(loginPath);
}
// All checks passed, allow access
return;
}
}