Files
whatsapp-inbox-platform/middleware.ts
Wira Basalamah 681e2667e4
Some checks failed
CI - Production Readiness / Verify (push) Has been cancelled
fix: respect next param on authenticated /login redirect
2026-04-21 13:27:10 +07:00

72 lines
2.7 KiB
TypeScript

import { NextResponse, type NextRequest } from "next/server";
import { canAccessPath, getDefaultPathForRole, parseSessionCookie, SESSION_COOKIE, type UserRole } from "@/lib/auth";
import { DEFAULT_LOCALE, isLocale, LOCALE_COOKIE } from "@/lib/i18n";
import { getRequestBaseUrl } from "@/lib/request-url";
const publicPaths = ["/login", "/forgot-password", "/reset-password", "/unauthorized", "/invite", "/auth"];
function isPublicPath(pathname: string) {
return publicPaths.some((path) => pathname === path || pathname.startsWith(`${path}/`));
}
async function decodeSessionCookie(value: string) {
return (await parseSessionCookie(value)) as null | { role: UserRole };
}
export async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
const baseUrl = getRequestBaseUrl(request);
const response = NextResponse.next();
if (pathname.startsWith("/_next") || pathname.includes(".")) {
return response;
}
const sessionCookie = request.cookies.get(SESSION_COOKIE)?.value;
const session = sessionCookie ? await decodeSessionCookie(sessionCookie) : null;
const localeCookie = request.cookies.get(LOCALE_COOKIE)?.value;
const acceptLanguage = request.headers.get("accept-language")?.toLowerCase() || "";
if (!localeCookie) {
const detected = acceptLanguage.includes("id") ? "id" : acceptLanguage.includes("en") ? "en" : DEFAULT_LOCALE;
response.cookies.set(LOCALE_COOKIE, detected, {
path: "/",
maxAge: 365 * 24 * 60 * 60,
secure: process.env.NODE_ENV === "production",
sameSite: "lax"
});
} else if (!isLocale(localeCookie)) {
response.cookies.set(LOCALE_COOKIE, DEFAULT_LOCALE, {
path: "/",
maxAge: 365 * 24 * 60 * 60,
secure: process.env.NODE_ENV === "production",
sameSite: "lax"
});
}
if (!session && !isPublicPath(pathname) && pathname !== "/") {
const loginUrl = new URL("/login", baseUrl);
loginUrl.searchParams.set("next", pathname);
return NextResponse.redirect(loginUrl);
}
if (session && (pathname === "/" || pathname === "/login")) {
const requested = request.nextUrl.searchParams.get("next");
const hasSafeNext = typeof requested === "string" && requested.startsWith("/") && !requested.startsWith("//");
const nextPath = hasSafeNext ? requested : null;
const destination = nextPath && canAccessPath(session.role, nextPath) ? nextPath : getDefaultPathForRole(session.role);
return NextResponse.redirect(new URL(destination, baseUrl));
}
if (session && !isPublicPath(pathname) && !canAccessPath(session.role, pathname)) {
return NextResponse.redirect(new URL("/unauthorized", baseUrl));
}
return response;
}
export const config = {
matcher: ["/((?!api).*)"]
};