const CONTROL_CHARS = /[\u0000-\u001f\u007f]/; function sanitizeHeaderValue(value: string, maxLength: number) { return value.replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, maxLength) || 'unknown'; } export function getClientAddress(headers: Headers) { const forwarded = headers.get('x-forwarded-for'); if (forwarded) { const addresses = forwarded .split(',') .map((value) => value.trim()) .filter(Boolean); if (addresses.length > 0) { // Use the nearest address. This avoids trusting a spoofed left-most value // when Next or a reverse proxy appends the real peer address. return sanitizeHeaderValue(addresses[addresses.length - 1], 128); } } const realIp = headers.get('x-real-ip'); if (realIp) return sanitizeHeaderValue(realIp, 128); return 'unknown'; } export function getUserAgent(headers: Headers) { return sanitizeHeaderValue(headers.get('user-agent') || 'unknown', 256); } export function normalizeVisitPath(value: unknown) { if (typeof value !== 'string') return null; const input = value.trim(); if ( input.length === 0 || input.length > 2048 || !input.startsWith('/') || input.startsWith('//') || CONTROL_CHARS.test(input) ) { return null; } try { const parsed = new URL(input, 'https://site.local'); if (parsed.origin !== 'https://site.local') return null; return `${parsed.pathname}${parsed.search}`; } catch { return null; } } export function isSameOriginRequest(request: Request) { const host = request.headers.get('host'); if (!host) return false; const requestHost = host.toLowerCase(); const origin = request.headers.get('origin'); if (origin) { try { return new URL(origin).host.toLowerCase() === requestHost; } catch { return false; } } const referer = request.headers.get('referer'); if (referer) { try { return new URL(referer).host.toLowerCase() === requestHost; } catch { return false; } } const fetchSite = request.headers.get('sec-fetch-site'); return fetchSite === 'same-origin' || fetchSite === 'none'; }