Files
sass-mohfarawati/middleware.ts
T

176 lines
5.0 KiB
TypeScript

import createMiddleware from "next-intl/middleware";
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
import { routing } from "./i18n/routing";
import {
fromDevelopmentAdminPath,
getAdminBaseUrl,
getRequestHostname,
isDevelopmentAdminPath,
isAdminHost,
hasDedicatedAdminHost,
isInternalAdminPath,
isLegacyAdminPath,
toInternalAdminPath,
} from "./lib/admin-routing";
import { getLocalizedPathWithDefault } from "./lib/locale";
const intlMiddleware = createMiddleware(routing);
async function getConfiguredDefaultLocale(request: NextRequest) {
try {
const response = await fetch(new URL("/api/site/default-locale", request.url), {
headers: {
"x-middleware-request": "1",
},
cache: "no-store",
});
if (!response.ok) {
return routing.defaultLocale;
}
const data = await response.json() as { defaultLocale?: string };
return data.defaultLocale === "ar" || data.defaultLocale === "en" || data.defaultLocale === "de"
? data.defaultLocale
: routing.defaultLocale;
} catch {
return routing.defaultLocale;
}
}
function hasLocalePrefix(pathname: string) {
return routing.locales.some((locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`));
}
function getAdminBasicAuthUser(): string {
return process.env.ADMIN_BASIC_AUTH_USER ?? "";
}
function getAdminBasicAuthPass(): string {
return process.env.ADMIN_BASIC_AUTH_PASS ?? "";
}
function isAdminBasicAuthConfigured(): boolean {
return Boolean(getAdminBasicAuthUser() && getAdminBasicAuthPass());
}
function isAdminBasicAuthValid(request: NextRequest): boolean {
if (!isAdminBasicAuthConfigured()) {
return false;
}
const header = request.headers.get("authorization");
if (!header || !header.startsWith("Basic ")) {
return false;
}
try {
const decoded = atob(header.slice(6));
const index = decoded.indexOf(":");
if (index === -1) {
return false;
}
const user = decoded.slice(0, index);
const pass = decoded.slice(index + 1);
return user === getAdminBasicAuthUser() && pass === getAdminBasicAuthPass();
} catch {
return false;
}
}
export default async function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
const isDevelopmentAdminRequest =
process.env.NODE_ENV !== "production" && isDevelopmentAdminPath(pathname);
const hostname = getRequestHostname(
request.headers.get("host") ?? request.headers.get("x-forwarded-host") ?? request.nextUrl.hostname,
);
const isAdminRequest = isDevelopmentAdminRequest || isAdminHost(hostname);
const hasDedicatedAdminHostname = hasDedicatedAdminHost();
const adminRobotsHeaders = {
"X-Robots-Tag": "noindex, nofollow, noarchive, nosnippet, noimageindex",
};
if (
isDevelopmentAdminRequest &&
hasDedicatedAdminHostname &&
!isAdminHost(hostname)
) {
const redirectUrl = new URL(getAdminBaseUrl());
redirectUrl.pathname = fromDevelopmentAdminPath(pathname);
redirectUrl.search = request.nextUrl.search;
return NextResponse.redirect(redirectUrl, 308);
}
if (isLegacyAdminPath(pathname) && process.env.NODE_ENV === "production") {
return new NextResponse("Not Found", {
status: 404,
});
}
if (isInternalAdminPath(pathname) && process.env.NODE_ENV === "production" && !isAdminRequest) {
return new NextResponse("Not Found", {
status: 404,
});
}
if (isAdminRequest) {
if (isAdminBasicAuthConfigured() && !isAdminBasicAuthValid(request)) {
return new NextResponse("Authentication required", {
status: 401,
headers: {
"WWW-Authenticate": 'Basic realm="Admin Area", charset="UTF-8"',
...adminRobotsHeaders,
},
});
}
const rewriteUrl = request.nextUrl.clone();
rewriteUrl.pathname = toInternalAdminPath(
isDevelopmentAdminRequest ? fromDevelopmentAdminPath(pathname) : pathname,
);
const response = NextResponse.rewrite(rewriteUrl);
response.headers.set("X-Robots-Tag", adminRobotsHeaders["X-Robots-Tag"]);
return response;
}
const configuredDefaultLocale = await getConfiguredDefaultLocale(request);
if (
configuredDefaultLocale !== routing.defaultLocale &&
(pathname === "/de" || pathname.startsWith("/de/"))
) {
return NextResponse.next();
}
if (
configuredDefaultLocale !== routing.defaultLocale &&
!hasLocalePrefix(pathname)
) {
const redirectUrl = request.nextUrl.clone();
redirectUrl.pathname = getLocalizedPathWithDefault(configuredDefaultLocale, pathname, routing.defaultLocale);
return NextResponse.redirect(redirectUrl, 307);
}
if (
configuredDefaultLocale === routing.defaultLocale &&
(pathname === "/de" || pathname.startsWith("/de/"))
) {
const redirectUrl = request.nextUrl.clone();
const nextPath = pathname.slice(3) || "/";
redirectUrl.pathname = nextPath;
return NextResponse.redirect(redirectUrl, 308);
}
return intlMiddleware(request);
}
export const config = {
matcher: ["/((?!api|trpc|_next|_vercel|.*\\..*).*)"],
};