Files
michaelswanson 860d5f55cc Initial commit
2026-06-25 19:58:40 +00:00

81 lines
2.1 KiB
JavaScript
Executable File

import dns from 'node:dns/promises';
import net from 'node:net';
// Värdnamn som medvetet tillåts trots att de pekar lokalt (t.ex. lokal Ollama).
export const LOCAL_ALLOWED_HOSTS = new Set([
'host.docker.internal',
'localhost',
'127.0.0.1',
'::1',
]);
function isPrivateIp(ip) {
if (net.isIPv4(ip)) {
const [a, b] = ip.split('.').map(Number);
return (
a === 10 ||
a === 127 ||
a === 0 ||
(a === 192 && b === 168) ||
(a === 172 && b >= 16 && b <= 31) ||
(a === 169 && b === 254) // link-local / cloud-metadata
);
}
if (net.isIPv6(ip)) {
const lower = ip.toLowerCase();
return (
lower === '::1' ||
lower === '::' ||
lower.startsWith('fc') ||
lower.startsWith('fd') ||
lower.startsWith('fe80') ||
lower.startsWith('::ffff:') // IPv4-mappad
);
}
return true; // okänt format → blockera
}
/**
* Validerar en URL mot SSRF. Kastar om adressen är ogiltig eller pekar internt.
* @param {string} rawUrl
* @param {{ allowList?: Set<string>, allowPrivateNetwork?: boolean }} [options] - värdnamn som tillåts trots privat IP
* @returns {Promise<URL>}
*/
export async function assertSafeUrl(rawUrl, { allowList = new Set(), allowPrivateNetwork = false } = {}) {
let url;
try {
url = new URL(String(rawUrl || ''));
} catch {
throw new Error('Ogiltig URL');
}
if (!['http:', 'https:'].includes(url.protocol)) {
throw new Error('Endast http/https tillåts');
}
if (allowList.has(url.hostname)) return url;
// Om värden redan är en literal IP behöver vi ingen DNS-lookup.
if (net.isIP(url.hostname)) {
if (!allowPrivateNetwork && isPrivateIp(url.hostname)) throw new Error('Adressen pekar mot ett internt nät');
return url;
}
let resolved;
try {
resolved = await dns.lookup(url.hostname, { all: true });
} catch {
throw new Error('Kunde inte slå upp värdnamnet');
}
if (!resolved.length) {
throw new Error('Kunde inte slå upp värdnamnet');
}
if (!allowPrivateNetwork && resolved.some(entry => isPrivateIp(entry.address))) {
throw new Error('Adressen pekar mot ett internt nät');
}
return url;
}