Forked from danielsig/visit-website
src / tls.ts
// Chrome 131+ Cipher Suite (Approximate order)
// This list mimics the TLS Client Hello of a modern Chrome browser.
const CHROME_CIPHERS = [
'TLS_AES_128_GCM_SHA256',
'TLS_AES_256_GCM_SHA384',
'TLS_CHACHA20_POLY1305_SHA256',
'ECDHE-ECDSA-AES128-GCM-SHA256',
'ECDHE-RSA-AES128-GCM-SHA256',
'ECDHE-ECDSA-AES256-GCM-SHA384',
'ECDHE-RSA-AES256-GCM-SHA384',
'ECDHE-ECDSA-CHACHA20-POLY1305',
'ECDHE-RSA-CHACHA20-POLY1305',
'ECDHE-RSA-AES128-SHA',
'ECDHE-RSA-AES256-SHA',
'AES128-GCM-SHA256',
'AES256-GCM-SHA384',
'AES128-SHA',
'AES256-SHA'
].join(':');
let globalDispatcher: any = undefined;
export async function configureUndiciDispatcher() {
if (globalDispatcher) return globalDispatcher;
try {
// Dynamically import undici to avoid crashes if it's not installed/available
// In Node 18+, undici is internal but often exposed via global 'undici' or 'Dispatcher' symbols
// If we are in an environment with the 'undici' package installed:
const undici = await import('undici').catch(() => null);
if (undici && undici.Agent && undici.setGlobalDispatcher) {
const agent = new undici.Agent({
// Vital: mimic browser connection behavior
connect: {
ciphers: CHROME_CIPHERS,
keepAlive: true,
timeout: 15000, // 15s timeout
},
pipelining: 1, // Browsers often pipeline
keepAliveTimeout: 10000,
keepAliveMaxTimeout: 10000,
});
undici.setGlobalDispatcher(agent);
globalDispatcher = agent;
console.log("Enhanced TLS fingerprinting enabled.");
}
} catch (e) {
// Fallback: If we can't configure undici, we just use default fetch.
// This usually happens if the environment is strict or 'undici' package is missing.
// In that case, we rely purely on headers.
}
return globalDispatcher;
}