File size: 1,935 Bytes
94193b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import { NextRequest, NextResponse } from 'next/server';
import { getIdentifier } from '@/lib/analytics/rate-limiter';
import { checkRateLimit } from '@/lib/web/rate-limit';

function getCookie(request: NextRequest, name: string): string | null {
  return request.cookies.get(name)?.value ?? null;
}

export function isSameOrigin(request: NextRequest): boolean {
  const host = request.headers.get('host') || '';
  const proto = request.headers.get('x-forwarded-proto') || 'https';
  const selfOrigin = `${proto}://${host}`;
  const origin = request.headers.get('origin') || '';
  const referer = request.headers.get('referer') || '';
  if (origin) return origin === selfOrigin;
  if (referer) return referer.startsWith(selfOrigin + '/') || referer === selfOrigin;
  return false;
}

/**
 * Shared preflight for the web proxy routes: kill-switch, same-origin,
 * server-mode session presence, and rate limiting. Returns either an rlKey
 * (all checks passed) or a ready-to-return error response.
 */
export function webRequestPreflight(
  request: NextRequest,
): { ok: true; rlKey: string } | { ok: false; response: NextResponse } {
  if (process.env.OSW_DISABLE_WEB_PROXY === '1') {
    return { ok: false, response: NextResponse.json({ error: 'web access is disabled on this instance' }, { status: 403 }) };
  }
  if (!isSameOrigin(request)) {
    return { ok: false, response: NextResponse.json({ error: 'origin not allowed' }, { status: 403 }) };
  }
  const workspace = getCookie(request, 'osw_workspace');
  if (process.env.NEXT_PUBLIC_SERVER_MODE === 'true' && !workspace) {
    return { ok: false, response: NextResponse.json({ error: 'authentication required' }, { status: 401 }) };
  }
  const rlKey = workspace || getIdentifier(request);
  if (!checkRateLimit(rlKey)) {
    return { ok: false, response: NextResponse.json({ error: 'rate limit exceeded, slow down' }, { status: 429 }) };
  }
  return { ok: true, rlKey };
}