edeb1eb148
v1.0.0:1 shipped a per-request nonce-based CSP via Next.js middleware. In production it produced a blank first paint: Next 14.2.x's bootstrap inline scripts weren't picking up the nonce reliably from the x-nonce request header, so the browser blocked them. This release reverts to the pre-experiment posture: - middleware.ts back to auth gating only (no nonce, no CSP). - next.config.js restores the static CSP with `'unsafe-inline'` allowed for script-src and style-src. Same headers (HSTS, Referrer-Policy, Permissions-Policy, frame-ancestors 'none', etc.) all stay. - New startos/versions/v1.0.0.2.ts with empty up/down migrations and a release note explaining the bug + revert. Promoted to `current` in the version graph; v1.0.0:1 moves to `other` so existing installs upgrade in place. No schema changes, no data migration. Existing v1.0.0:1 installs keep their /data. Re-attempt path documented in middleware.ts and next.config.js comments: future PR can revisit nonce CSP using Next's documented pattern verbatim (notably setting CSP on BOTH request headers and response headers — we only set it on response).
50 lines
1.7 KiB
TypeScript
50 lines
1.7 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
|
|
/**
|
|
* Auth gating only.
|
|
*
|
|
* Previously this also generated a per-request nonce and set a strict
|
|
* Content-Security-Policy header. That broke first-paint in production
|
|
* (Next 14.2.x): the bootstrap inline scripts in SSR'd HTML weren't
|
|
* picking up the nonce from `x-nonce` reliably, and the resulting
|
|
* CSP-blocked script left a blank page.
|
|
*
|
|
* Reverted to: middleware does auth gating, CSP is set statically in
|
|
* next.config.js with `'unsafe-inline'` allowed for script + style.
|
|
* That's the same posture we shipped successfully through v1.0.0:1's
|
|
* first cutover smoke build before this experiment.
|
|
*
|
|
* Re-attempt path (later): use Next's documented nonce middleware
|
|
* pattern verbatim, including setting the CSP on BOTH request headers
|
|
* and response headers (the example in
|
|
* https://nextjs.org/docs/app/building-your-application/configuring/content-security-policy
|
|
* sets it on both — we only set it on response, which may be the
|
|
* miss). Test in a real browser before shipping.
|
|
*/
|
|
export function middleware(request: NextRequest) {
|
|
const { pathname } = request.nextUrl;
|
|
const sessionToken = request.cookies.get('sessionToken')?.value;
|
|
|
|
if (pathname.startsWith('/main') && !sessionToken) {
|
|
return NextResponse.redirect(new URL('/auth/login', request.url));
|
|
}
|
|
|
|
if (pathname.startsWith('/api')) {
|
|
if (
|
|
pathname.startsWith('/api/auth') ||
|
|
pathname.startsWith('/api/health')
|
|
) {
|
|
return NextResponse.next();
|
|
}
|
|
if (!sessionToken) {
|
|
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
|
|
}
|
|
}
|
|
|
|
return NextResponse.next();
|
|
}
|
|
|
|
export const config = {
|
|
matcher: ['/main/:path*', '/api/:path*'],
|
|
};
|