car_mms/app/lib/auth-middleware.server.ts
2025-09-11 14:22:27 +03:00

173 lines
4.9 KiB
TypeScript

import { redirect } from "@remix-run/node";
import { getUser, requireUserId } from "./auth.server";
import { requireAuthLevel } from "./auth-helpers.server";
import type { AuthLevel, SafeUser, RouteProtectionOptions } from "~/types/auth";
import { AUTH_LEVELS, USER_STATUS } from "~/types/auth";
import { AUTH_ERRORS } from "./auth-constants";
// Enhanced middleware for protecting routes that require authentication
export async function requireAuthentication(
request: Request,
options: RouteProtectionOptions = {}
): Promise<SafeUser> {
const { allowInactive = false, redirectTo = "/signin" } = options;
await requireUserId(request, redirectTo);
const user = await getUser(request);
if (!user) {
throw redirect(redirectTo);
}
// Check if user is active (unless explicitly allowed)
if (!allowInactive && user.status !== USER_STATUS.ACTIVE) {
throw redirect("/signin?error=account_inactive");
}
return user;
}
// Middleware for protecting admin routes (admin and superadmin)
export async function requireAdmin(
request: Request,
options: RouteProtectionOptions = {}
): Promise<SafeUser> {
return requireAuthLevel(request, AUTH_LEVELS.ADMIN, options);
}
// Middleware for protecting superadmin routes
export async function requireSuperAdmin(
request: Request,
options: RouteProtectionOptions = {}
): Promise<SafeUser> {
return requireAuthLevel(request, AUTH_LEVELS.SUPERADMIN, options);
}
// Middleware for protecting routes with custom auth level
export async function requireAuth(
request: Request,
authLevel: AuthLevel,
options: RouteProtectionOptions = {}
): Promise<SafeUser> {
return requireAuthLevel(request, authLevel, options);
}
// Middleware for redirecting authenticated users away from auth pages
export async function redirectIfAuthenticated(
request: Request,
redirectTo: string = "/dashboard"
) {
const user = await getUser(request);
if (user && user.status === USER_STATUS.ACTIVE) {
throw redirect(redirectTo);
}
}
// Middleware for optional authentication (user may or may not be logged in)
export async function getOptionalUser(request: Request): Promise<SafeUser | null> {
try {
const user = await getUser(request);
return user && user.status === USER_STATUS.ACTIVE ? user : null;
} catch {
return null;
}
}
// Session validation middleware
export async function validateSession(request: Request): Promise<{
isValid: boolean;
user: SafeUser | null;
error?: string;
}> {
try {
const user = await getUser(request);
if (!user) {
return {
isValid: false,
user: null,
error: "no_user",
};
}
if (user.status !== USER_STATUS.ACTIVE) {
return {
isValid: false,
user: null,
error: "inactive_user",
};
}
return {
isValid: true,
user,
};
} catch {
return {
isValid: false,
user: null,
error: "session_error",
};
}
}
// Route-specific protection functions
export async function protectUserManagementRoute(request: Request): Promise<SafeUser> {
const user = await requireAdmin(request);
// Additional business logic: ensure user can manage users
if (user.authLevel > AUTH_LEVELS.ADMIN) {
throw redirect("/dashboard?error=insufficient_permissions");
}
return user;
}
export async function protectFinancialRoute(request: Request): Promise<SafeUser> {
// Financial routes require at least admin level
return requireAdmin(request);
}
export async function protectCustomerRoute(request: Request): Promise<SafeUser> {
// Customer routes require authentication but any auth level can access
return requireAuthentication(request);
}
export async function protectVehicleRoute(request: Request): Promise<SafeUser> {
// Vehicle routes require authentication but any auth level can access
return requireAuthentication(request);
}
export async function protectMaintenanceRoute(request: Request): Promise<SafeUser> {
// Maintenance routes require authentication but any auth level can access
return requireAuthentication(request);
}
// Utility function to check specific permissions
export function checkPermission(
user: SafeUser,
permission: 'view_all_users' | 'create_users' | 'manage_finances' | 'view_reports'
): boolean {
switch (permission) {
case 'view_all_users':
return user.authLevel === AUTH_LEVELS.SUPERADMIN;
case 'create_users':
return user.authLevel <= AUTH_LEVELS.ADMIN;
case 'manage_finances':
return user.authLevel <= AUTH_LEVELS.ADMIN;
case 'view_reports':
return user.authLevel <= AUTH_LEVELS.ADMIN;
default:
return false;
}
}
// Error handling for unauthorized access
export function createUnauthorizedResponse(message?: string) {
const errorMessage = message || AUTH_ERRORS.INSUFFICIENT_PERMISSIONS;
return new Response(errorMessage, {
status: 403,
headers: {
'Content-Type': 'text/plain; charset=utf-8'
}
});
}