40 lines
1.2 KiB
TypeScript
40 lines
1.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import type { NextRequest } from "next/server";
|
|
import { canAccess, requiresAuth, requiresAdmin } from "./lib/rbac";
|
|
import type { Role } from "@public-web-portals/shared";
|
|
|
|
const LOGIN = "/login";
|
|
|
|
function getRoleFromCookie(request: NextRequest): Role | null {
|
|
const role = request.cookies.get("portal-role")?.value;
|
|
if (!role) return null;
|
|
const valid: Role[] = ["member", "judge", "clerk", "diplomat", "donor", "staff", "admin"];
|
|
return valid.includes(role as Role) ? (role as Role) : null;
|
|
}
|
|
|
|
export function middleware(request: NextRequest) {
|
|
const pathname = request.nextUrl.pathname;
|
|
const role = getRoleFromCookie(request);
|
|
|
|
if (requiresAdmin(pathname) && role !== "admin") {
|
|
return NextResponse.redirect(new URL("/dashboard", request.url));
|
|
}
|
|
|
|
if (requiresAuth(pathname)) {
|
|
if (role == null) {
|
|
const url = new URL(LOGIN, request.url);
|
|
url.searchParams.set("returnUrl", pathname);
|
|
return NextResponse.redirect(url);
|
|
}
|
|
if (!canAccess(pathname, role)) {
|
|
return NextResponse.redirect(new URL("/dashboard", request.url));
|
|
}
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ["/((?!_next/static|_next/image|favicon.ico|api).*)"],
|
|
};
|