Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions frontend/src/app/profile/[username]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { notFound } from "next/navigation";
import { headers } from "next/headers";
import type { Metadata } from "next";
import { AppShell } from "@/components/app-shell";
import { ProfileCard } from "@/components/profile-card";
Expand Down Expand Up @@ -251,13 +250,10 @@ export default async function ProfilePage({ params }: PageProps) {
},
};

const nonce = headers().get("x-csp-nonce") ?? undefined;

return (
<AppShell>
<script
type="application/ld+json"
nonce={nonce}
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<div className="grid grid-cols-1 lg:grid-cols-[1fr_380px] gap-8 items-start animate-fade-in">
Expand Down
14 changes: 2 additions & 12 deletions frontend/src/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,17 @@ import type { NextRequest } from "next/server";
// since process.env there is only resolved at build time and would bake in
// an empty connect-src on hosts where these vars are injected at runtime.
export function middleware(request: NextRequest) {
// Per-request nonce so server-rendered inline scripts (e.g. the JSON-LD
// structured-data block on profile pages) can be allow-listed individually
// under the strict `script-src 'self'` policy below.
const nonce = Buffer.from(crypto.randomUUID()).toString("base64");
const response = NextResponse.next();

const csp = [
"default-src 'self'",
`script-src 'self' 'nonce-${nonce}'`,
"script-src 'self'",
"style-src 'self' 'unsafe-inline'",
`connect-src 'self' ${process.env.NEXT_PUBLIC_API_BASE_URL ?? ""} ${process.env.NEXT_PUBLIC_HORIZON_URL ?? ""} ${process.env.NEXT_PUBLIC_SOROBAN_RPC_URL ?? ""}`,
"img-src 'self' data: blob: https:",
"frame-ancestors 'none'",
].join("; ");

const requestHeaders = new Headers(request.headers);
requestHeaders.set("x-csp-nonce", nonce);

const response = NextResponse.next({
request: { headers: requestHeaders },
});

response.headers.set("Content-Security-Policy", csp);

return response;
Expand Down
Loading