Leon4gr45/builder
0
1import { NextRequest, NextResponse } from 'next/server';2import { getIdentifier } from '@/lib/analytics/rate-limiter';3import { checkRateLimit } from '@/lib/web/rate-limit';4 5function getCookie(request: NextRequest, name: string): string | null {6 return request.cookies.get(name)?.value ?? null;7}8 9export function isSameOrigin(request: NextRequest): boolean {10 const host = request.headers.get('host') || '';11 const proto = request.headers.get('x-forwarded-proto') || 'https';12 const selfOrigin = `${proto}://${host}`;13 const origin = request.headers.get('origin') || '';14 const referer = request.headers.get('referer') || '';15 if (origin) return origin === selfOrigin;16 if (referer) return referer.startsWith(selfOrigin + '/') || referer === selfOrigin;17 return false;18}19 20/**21 * Shared preflight for the web proxy routes: kill-switch, same-origin,22 * server-mode session presence, and rate limiting. Returns either an rlKey23 * (all checks passed) or a ready-to-return error response.24 */25export function webRequestPreflight(26 request: NextRequest,27): { ok: true; rlKey: string } | { ok: false; response: NextResponse } {28 if (process.env.OSW_DISABLE_WEB_PROXY === '1') {29 return { ok: false, response: NextResponse.json({ error: 'web access is disabled on this instance' }, { status: 403 }) };30 }31 if (!isSameOrigin(request)) {32 return { ok: false, response: NextResponse.json({ error: 'origin not allowed' }, { status: 403 }) };33 }34 const workspace = getCookie(request, 'osw_workspace');35 if (process.env.NEXT_PUBLIC_SERVER_MODE === 'true' && !workspace) {36 return { ok: false, response: NextResponse.json({ error: 'authentication required' }, { status: 401 }) };37 }38 const rlKey = workspace || getIdentifier(request);39 if (!checkRateLimit(rlKey)) {40 return { ok: false, response: NextResponse.json({ error: 'rate limit exceeded, slow down' }, { status: 429 }) };41 }42 return { ok: true, rlKey };43}44 