From b038efa58b29a655e8bcabed28b14b461f579b1a Mon Sep 17 00:00:00 2001 From: Danyal Prout Date: Tue, 25 Aug 2026 16:41:29 -0500 Subject: [PATCH 1/2] chore: remove temporary site password gate Removes the temporary site-wide password gate (middleware.ts and app/api/gate/route.ts) now that it's no longer needed. Co-Authored-By: Claude --- app/api/gate/route.ts | 43 ---------------- middleware.ts | 112 ------------------------------------------ 2 files changed, 155 deletions(-) delete mode 100644 app/api/gate/route.ts delete mode 100644 middleware.ts diff --git a/app/api/gate/route.ts b/app/api/gate/route.ts deleted file mode 100644 index 6cd1b78..0000000 --- a/app/api/gate/route.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { NextResponse } from 'next/server'; - -// Verifies the temporary site password (see middleware.ts) and, on success, -// sets an httpOnly cookie that the middleware checks. Reads the password from -// SITE_PASSWORD; nothing is hardcoded. - -export const runtime = 'nodejs'; - -const COOKIE = 'site_gate'; -const MAX_AGE_SECONDS = 60 * 60 * 24 * 7; // 7 days - -export async function POST(request: Request) { - const password = process.env.SITE_PASSWORD; - - // Gate disabled (no password configured) -> nothing to verify. - if (!password) { - return NextResponse.json({ ok: true }); - } - - let provided = ''; - try { - const body: unknown = await request.json(); - if (body && typeof body === 'object' && 'password' in body) { - provided = String((body as { password: unknown }).password); - } - } catch { - provided = ''; - } - - if (provided !== password) { - return NextResponse.json({ ok: false }, { status: 401 }); - } - - const res = NextResponse.json({ ok: true }); - res.cookies.set(COOKIE, password, { - httpOnly: true, - secure: true, - sameSite: 'strict', - path: '/', - maxAge: MAX_AGE_SECONDS, - }); - return res; -} diff --git a/middleware.ts b/middleware.ts deleted file mode 100644 index d78502c..0000000 --- a/middleware.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server'; - -import { disabledRoutePrefixes } from './deploy.config.mjs'; - -// TEMPORARY site-wide password gate. -// -// Active only when SITE_PASSWORD is set. Set it in Vercel's Production -// environment so the gate shows on production only; leave it unset for local -// dev and preview. The password itself is never committed — it lives in the -// env var. -// -// The gate covers UI pages only. /api/* is intentionally left public so the -// snapshots API stays reachable by external consumers. -// -// To remove the gate later: delete this file and app/api/gate/route.ts, and -// unset SITE_PASSWORD in Vercel. - -const COOKIE = 'site_gate'; - -export function middleware(req: NextRequest) { - // Surfaces not shipped to this build target (deploy.config.mjs) 404 at the - // edge. This is the authoritative status block: a disabled section's page may - // be statically prerendered, so its layout notFound() serves 404 content with - // a 200 status — enforcing the real 404 here, before the static asset is - // served. Prefixes are build-time constant (target is inlined). - const { pathname } = req.nextUrl; - for (const prefix of disabledRoutePrefixes()) { - if (pathname === prefix || pathname.startsWith(`${prefix}/`)) { - return new NextResponse('Not Found', { status: 404 }); - } - } - - const password = process.env.SITE_PASSWORD; - - // No password configured (local dev / preview) -> no gate. - if (!password || process.env.NODE_ENV === 'development') { - return NextResponse.next(); - } - - if (req.cookies.get(COOKIE)?.value === password) { - return NextResponse.next(); - } - - return new NextResponse(gateHtml(), { - status: 401, - headers: { - 'content-type': 'text/html; charset=utf-8', - 'cache-control': 'no-store', - }, - }); -} - -// Match everything except the public API, Next internals, and static assets. -export const config = { - matcher: ['/((?!api/|_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)'], -}; - -// Self-contained gate screen (no app layout / external assets), posts the -// password to /api/gate and reloads on success. -function gateHtml(): string { - return ` - - - - - -Base Chain - - - -
-

Base Chain

-

Coming soon: tools and dashboards for Base Chain

- - -
-
- - -`; -} From a8e78aecddd22e6e311fc4f8a0aa7dccdfea746b Mon Sep 17 00:00:00 2001 From: Danyal Prout Date: Tue, 25 Aug 2026 16:47:21 -0500 Subject: [PATCH 2/2] fix: restore build-target route gating in middleware Removing the temporary password gate also removed middleware.ts entirely, but that file had a second, unrelated job: 404ing routes disabled for the current deploy target (deploy.config.mjs). Restore that logic without the password gate. Co-Authored-By: Claude --- middleware.ts | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 middleware.ts diff --git a/middleware.ts b/middleware.ts new file mode 100644 index 0000000..f9a62b0 --- /dev/null +++ b/middleware.ts @@ -0,0 +1,24 @@ +import { NextRequest, NextResponse } from 'next/server'; + +import { disabledRoutePrefixes } from './deploy.config.mjs'; + +export function middleware(req: NextRequest) { + // Surfaces not shipped to this build target (deploy.config.mjs) 404 at the + // edge. This is the authoritative status block: a disabled section's page may + // be statically prerendered, so its layout notFound() serves 404 content with + // a 200 status — enforcing the real 404 here, before the static asset is + // served. Prefixes are build-time constant (target is inlined). + const { pathname } = req.nextUrl; + for (const prefix of disabledRoutePrefixes()) { + if (pathname === prefix || pathname.startsWith(`${prefix}/`)) { + return new NextResponse('Not Found', { status: 404 }); + } + } + + return NextResponse.next(); +} + +// Match everything except the public API, Next internals, and static assets. +export const config = { + matcher: ['/((?!api/|_next/static|_next/image|favicon.ico|robots.txt|sitemap.xml).*)'], +};