Harden onion boot flow and deepen site surfaces
Add persistent onion key backup and restore, improve startup resilience, and flesh out the major site verticals with richer navigation, search coverage, and operator documentation. Made-with: Cursor
This commit is contained in:
144
proxy.ts
Normal file
144
proxy.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
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";
|
||||
|
||||
/** 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"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Paths that must not be prefixed when using a dedicated entry onion.
|
||||
* Keep in sync with top-level `app/<segment>/` routes.
|
||||
*/
|
||||
const CROSS_NAV_PREFIXES = [
|
||||
"/account",
|
||||
"/api",
|
||||
"/arb-academy",
|
||||
"/awards",
|
||||
"/barter",
|
||||
"/chatter",
|
||||
"/checkout",
|
||||
"/comparison",
|
||||
"/conspiracies",
|
||||
"/darknet-atlas",
|
||||
"/dashboard",
|
||||
"/drop-box",
|
||||
"/drops",
|
||||
"/easter-eggs",
|
||||
"/exchange",
|
||||
"/forum",
|
||||
"/game",
|
||||
"/hidden-wiki",
|
||||
"/inner-circle",
|
||||
"/links",
|
||||
"/market",
|
||||
"/messages",
|
||||
"/mixer",
|
||||
"/presswire",
|
||||
"/raffle",
|
||||
"/red-room",
|
||||
"/reviews",
|
||||
"/sanctuary",
|
||||
"/search",
|
||||
"/secret-layer",
|
||||
"/security-analysis",
|
||||
"/sign-in",
|
||||
"/sign-up",
|
||||
"/support",
|
||||
"/syndicate",
|
||||
"/testimonials",
|
||||
"/trees",
|
||||
"/trust",
|
||||
"/vault",
|
||||
"/vendor",
|
||||
"/vendors",
|
||||
"/wallets",
|
||||
"/webring",
|
||||
"/w/",
|
||||
] as const;
|
||||
|
||||
function isCrossNavPath(pathname: string): boolean {
|
||||
return CROSS_NAV_PREFIXES.some((p) => pathname.startsWith(p));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user