This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
|
||||
// One nonce per request, and the security headers of spec §6.4 on every response.
|
||||
//
|
||||
// `proxy.ts` is Next.js 16's name for what used to be `middleware.ts`; the older name still
|
||||
// works and warns, so the template uses the current one.
|
||||
//
|
||||
// The policy is also set on the *request* headers, which is how Next.js finds the nonce for the
|
||||
// scripts it injects itself; `x-nonce` is there for a layout that renders a script of its own.
|
||||
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
import { contentSecurityPolicy, securityHeaders } from "./src/server/headers"
|
||||
|
||||
export default function proxy(request: NextRequest): NextResponse {
|
||||
const nonce = Buffer.from(globalThis.crypto.randomUUID()).toString("base64")
|
||||
const secure = request.nextUrl.protocol === "https:"
|
||||
const development = process.env.NODE_ENV === "development"
|
||||
const policy = contentSecurityPolicy({ nonce, development })
|
||||
|
||||
const headers = new Headers(request.headers)
|
||||
headers.set("x-nonce", nonce)
|
||||
// Where this request is, for a page that has to send a visitor to sign in and bring them back: a
|
||||
// server component is not given its own URL.
|
||||
headers.set("x-path", `${request.nextUrl.pathname}${request.nextUrl.search}`)
|
||||
headers.set("content-security-policy", policy)
|
||||
|
||||
const response = NextResponse.next({ request: { headers } })
|
||||
for (const [name, value] of Object.entries(securityHeaders({ nonce, secure, development }))) {
|
||||
response.headers.set(name, value)
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
{
|
||||
// Everything but the build's own immutable assets, which carry no HTML and no script of their own.
|
||||
source: "/((?!_next/static|_next/image|favicon.svg).*)",
|
||||
// ...and but a request whose body is a stream of bytes (`PUT /api/v1/<procedure>` of a
|
||||
// procedure declared with `.stream(field)`, the pieces of a file upload). Next.js buffers the
|
||||
// body of every request this proxy runs for and drops what is past `proxyClientMaxBodySize`
|
||||
// (10 MB), so a 30 MB file would reach its route cut short and fail its length check. The
|
||||
// response of that route is JSON, which needs no nonce and no policy for a page; the router
|
||||
// sets the headers that matter for JSON itself (router.ts).
|
||||
missing: [{ type: "header", key: "content-type", value: "application/octet-stream" }],
|
||||
},
|
||||
],
|
||||
}
|
||||
Reference in New Issue
Block a user