Capture the current CyberLux UI, commerce, messaging, and Tor ops updates so local main can be pushed to the remote. Made-with: Cursor
95 lines
2.7 KiB
TypeScript
95 lines
2.7 KiB
TypeScript
import { NextResponse } from "next/server";
|
|
import type { NextRequest } from "next/server";
|
|
import {
|
|
CYBERLUX_ENTRY_COOKIE,
|
|
parseCyberluxEntry,
|
|
type CyberluxEntry,
|
|
} from "@/lib/cyberluxEntry";
|
|
import { DEDICATED_ROOT } from "@/lib/onionRoutes.generated";
|
|
import { isOnionCrossNavPath } from "@/lib/cyberluxCrossNav";
|
|
|
|
/** Set by nginx per Tor vhost: `proxy_set_header X-Cyberlux-Node <node>;` */
|
|
function entryFromRequest(request: NextRequest): CyberluxEntry {
|
|
return parseCyberluxEntry(request.headers.get("x-cyberlux-node"));
|
|
}
|
|
|
|
function isCrossNavPath(pathname: string): boolean {
|
|
return isOnionCrossNavPath(pathname);
|
|
}
|
|
|
|
function withEntryCookie(res: NextResponse, request: NextRequest): NextResponse {
|
|
const entry = entryFromRequest(request);
|
|
res.cookies.set(CYBERLUX_ENTRY_COOKIE, entry, {
|
|
path: "/",
|
|
sameSite: "lax",
|
|
maxAge: 60 * 60 * 24 * 400,
|
|
httpOnly: false,
|
|
});
|
|
return res;
|
|
}
|
|
|
|
function handleDedicatedRoot(
|
|
request: NextRequest,
|
|
pathname: string,
|
|
root: string,
|
|
): NextResponse {
|
|
if (isCrossNavPath(pathname)) {
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|
|
const suffix = pathname === "/" ? "" : pathname;
|
|
return withEntryCookie(
|
|
NextResponse.rewrite(new URL(`${root}${suffix}`, request.url)),
|
|
request,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Next.js 16+ proxy (replaces `middleware.ts`). Runs on Node; no `export const config` here.
|
|
*/
|
|
export function proxy(request: NextRequest) {
|
|
const { pathname } = request.nextUrl;
|
|
const entry = entryFromRequest(request);
|
|
|
|
if (pathname.startsWith("/_next") || pathname.startsWith("/favicon")) {
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|
|
// Same idea as legacy middleware `matcher`: skip typical static files
|
|
if (/\.[a-zA-Z0-9]{2,5}$/.test(pathname)) {
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|
|
|
|
if (entry === "wiki") {
|
|
if (isCrossNavPath(pathname)) {
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|
|
return withEntryCookie(
|
|
NextResponse.rewrite(new URL("/hidden-wiki", request.url)),
|
|
request,
|
|
);
|
|
}
|
|
|
|
if (entry === "w") {
|
|
if (isCrossNavPath(pathname)) {
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|
|
if (pathname === "/") {
|
|
return withEntryCookie(
|
|
NextResponse.rewrite(new URL("/syndicate", request.url)),
|
|
request,
|
|
);
|
|
}
|
|
const rest = pathname.startsWith("/") ? pathname.slice(1) : pathname;
|
|
return withEntryCookie(
|
|
NextResponse.rewrite(new URL(`/w/${rest}`, request.url)),
|
|
request,
|
|
);
|
|
}
|
|
|
|
if (entry !== "hub" && entry in DEDICATED_ROOT) {
|
|
const root = DEDICATED_ROOT[entry as keyof typeof DEDICATED_ROOT];
|
|
return handleDedicatedRoot(request, pathname, root);
|
|
}
|
|
|
|
return withEntryCookie(NextResponse.next(), request);
|
|
}
|