- Looking for a starting point or more instructions? Head over to{" "}
-
- Templates
- {" "}
- or the{" "}
-
- Learning
- {" "}
- center.
-
+
+
+
Ops Dashboard
+
Welkom {user.email}
-
- );
+ )
}
diff --git a/middleware.ts b/middleware.ts
deleted file mode 100644
index 99f0bae..0000000
--- a/middleware.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { NextRequest, NextResponse } from 'next/server'
-
-const CSP = [
- "default-src 'self'",
- "script-src 'self' 'unsafe-inline'",
- "style-src 'self' 'unsafe-inline'",
- "font-src 'self'",
- "img-src 'self' data:",
- "connect-src 'self'",
- "frame-ancestors 'none'",
- "base-uri 'self'",
- "form-action 'self'",
-].join('; ')
-
-const CSRF_COOKIE = 'csrf_token'
-const CSRF_HEADER = 'x-csrf-token'
-
-export function middleware(request: NextRequest) {
- const { method, nextUrl } = request
-
- // Validate CSRF token on all POST requests to API routes
- if (method === 'POST' && nextUrl.pathname.startsWith('/api/')) {
- const cookieToken = request.cookies.get(CSRF_COOKIE)?.value
- const headerToken = request.headers.get(CSRF_HEADER)
- if (!cookieToken || cookieToken !== headerToken) {
- return new NextResponse(
- JSON.stringify({ error: 'CSRF validation failed' }),
- { status: 403, headers: { 'Content-Type': 'application/json' } },
- )
- }
- }
-
- const response = NextResponse.next()
-
- response.headers.set('Content-Security-Policy', CSP)
- response.headers.set('X-Frame-Options', 'DENY')
- response.headers.set('X-Content-Type-Options', 'nosniff')
- response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
-
- // Issue a CSRF token cookie on GET requests when not yet present
- if (method === 'GET' && !request.cookies.get(CSRF_COOKIE)) {
- response.cookies.set(CSRF_COOKIE, crypto.randomUUID(), {
- httpOnly: false, // must be readable by client JS for the double-submit pattern
- sameSite: 'strict',
- secure: process.env.NODE_ENV === 'production',
- path: '/',
- })
- }
-
- return response
-}
-
-export const config = {
- matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
-}
diff --git a/proxy.ts b/proxy.ts
index e2b24d3..2f902de 100644
--- a/proxy.ts
+++ b/proxy.ts
@@ -2,22 +2,66 @@ import { NextRequest, NextResponse } from 'next/server'
const PUBLIC_PATHS = ['/login']
+const CSP = [
+ "default-src 'self'",
+ "script-src 'self' 'unsafe-inline'",
+ "style-src 'self' 'unsafe-inline'",
+ "font-src 'self'",
+ "img-src 'self' data:",
+ "connect-src 'self'",
+ "frame-ancestors 'none'",
+ "base-uri 'self'",
+ "form-action 'self'",
+].join('; ')
+
+const CSRF_COOKIE = 'csrf_token'
+const CSRF_HEADER = 'x-csrf-token'
+
export default function proxy(request: NextRequest) {
- const { pathname } = request.nextUrl
- const isPublic = PUBLIC_PATHS.some((p) => pathname.startsWith(p))
- const hasSession = request.cookies.has('ops_session')
+ const { method, nextUrl } = request
+ const { pathname } = nextUrl
- if (!isPublic && !hasSession) {
- return NextResponse.redirect(new URL('/login', request.url))
+ if (method === 'POST' && pathname.startsWith('/api/')) {
+ const cookieToken = request.cookies.get(CSRF_COOKIE)?.value
+ const headerToken = request.headers.get(CSRF_HEADER)
+ if (!cookieToken || cookieToken !== headerToken) {
+ return new NextResponse(
+ JSON.stringify({ error: 'CSRF validation failed' }),
+ { status: 403, headers: { 'Content-Type': 'application/json' } },
+ )
+ }
}
- if (isPublic && hasSession) {
- return NextResponse.redirect(new URL('/', request.url))
+ if (!pathname.startsWith('/api/')) {
+ const isPublic = PUBLIC_PATHS.some((p) => pathname.startsWith(p))
+ const hasSession = request.cookies.has('ops_session')
+ if (!isPublic && !hasSession) {
+ return NextResponse.redirect(new URL('/login', request.url))
+ }
+ if (isPublic && hasSession) {
+ return NextResponse.redirect(new URL('/', request.url))
+ }
}
- return NextResponse.next()
+ const response = NextResponse.next()
+
+ response.headers.set('Content-Security-Policy', CSP)
+ response.headers.set('X-Frame-Options', 'DENY')
+ response.headers.set('X-Content-Type-Options', 'nosniff')
+ response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
+
+ if (method === 'GET' && !request.cookies.get(CSRF_COOKIE)) {
+ response.cookies.set(CSRF_COOKIE, crypto.randomUUID(), {
+ httpOnly: false,
+ sameSite: 'strict',
+ secure: process.env.NODE_ENV === 'production',
+ path: '/',
+ })
+ }
+
+ return response
}
export const config = {
- matcher: ['/((?!api|_next/static|_next/image|.*\\.(?:png|ico|svg)$).*)'],
+ matcher: ['/((?!_next/static|_next/image|favicon.ico|.*\\.(?:png|ico|svg)$).*)'],
}