This commit is contained in:
80
lib/request.ts
Normal file
80
lib/request.ts
Normal file
@@ -0,0 +1,80 @@
|
||||
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';
|
||||
}
|
||||
Reference in New Issue
Block a user