import { UserAgentUtil } from './user-agent.util'; export class HeadersUtil { private static readonly ACCEPT_LANGUAGES = [ 'en-US,en;q=0.9', 'en-GB,en;q=0.9', 'en-US,en;q=0.8,es;q=0.7', 'en-GB,en;q=0.8,fr;q=0.6', 'es-ES,es;q=0.9,en;q=0.8', 'fr-FR,fr;q=0.9,en;q=0.8', 'de-DE,de;q=0.9,en;q=0.8', 'it-IT,it;q=0.9,en;q=0.8', 'pt-PT,pt;q=0.9,en;q=0.8', 'ru-RU,ru;q=0.9,en;q=0.8', 'ja-JP,ja;q=0.9,en;q=0.8', 'ko-KR,ko;q=0.9,en;q=0.8', 'zh-CN,zh;q=0.9,en;q=0.8', 'nl-NL,nl;q=0.9,en;q=0.8', 'sv-SE,sv;q=0.9,en;q=0.8', 'da-DK,da;q=0.9,en;q=0.8', 'no-NO,no;q=0.9,en;q=0.8', 'fi-FI,fi;q=0.9,en;q=0.8', 'pl-PL,pl;q=0.9,en;q=0.8', 'tr-TR,tr;q=0.9,en;q=0.8', ]; private static readonly ACCEPT_ENCODINGS = [ 'gzip, deflate, br', 'gzip, deflate', 'br, gzip, deflate', 'gzip, deflate, br, zstd', 'br', 'gzip', 'deflate', 'identity', 'gzip, deflate, sdch', 'br, gzip', 'deflate, br', 'gzip, br', ]; private static readonly ACCEPT_HEADERS = [ 'application/json, text/plain, */*', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'application/json, text/javascript, */*; q=0.01', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7', '*/*', 'application/json', 'text/html, */*; q=0.01', 'application/json, text/plain', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', ]; private static readonly CONNECTION_TYPES = ['keep-alive', 'close', 'upgrade']; private static readonly CACHE_CONTROL_VALUES = [ 'no-cache', 'max-age=0', 'no-cache, no-store, must-revalidate', 'public, max-age=0', 'private, max-age=0', 'no-store', 'max-age=300', 'max-age=3600', ]; private static readonly SEC_FETCH_DEST_VALUES = [ 'empty', 'document', 'script', 'style', 'image', 'font', 'object', 'embed', 'iframe', 'worker', 'sharedworker', 'serviceworker', 'audioworklet', 'paintworklet', 'manifest', 'nested-document', 'report', 'xslt', ]; private static readonly SEC_FETCH_MODE_VALUES = [ 'cors', 'no-cors', 'same-origin', 'navigate', 'websocket', ]; private static readonly SEC_FETCH_SITE_VALUES = [ 'cross-site', 'same-origin', 'same-site', 'none', ]; static getRandomHeaders(): Record { const headers: Record = { Accept: this.getRandomArrayElement(this.ACCEPT_HEADERS), 'User-Agent': UserAgentUtil.getRandomUserAgent(), 'Accept-Language': this.getRandomArrayElement(this.ACCEPT_LANGUAGES), 'Accept-Encoding': this.getRandomArrayElement(this.ACCEPT_ENCODINGS), Connection: this.getRandomArrayElement(this.CONNECTION_TYPES), DNT: Math.random() > 0.5 ? '1' : '0', }; // Randomly add optional headers if (Math.random() > 0.3) { headers['Cache-Control'] = this.getRandomArrayElement( this.CACHE_CONTROL_VALUES, ); } if (Math.random() > 0.5) { headers['Pragma'] = 'no-cache'; } if (Math.random() > 0.4) { headers['Sec-Fetch-Dest'] = this.getRandomArrayElement( this.SEC_FETCH_DEST_VALUES, ); headers['Sec-Fetch-Mode'] = this.getRandomArrayElement( this.SEC_FETCH_MODE_VALUES, ); headers['Sec-Fetch-Site'] = this.getRandomArrayElement( this.SEC_FETCH_SITE_VALUES, ); } if (Math.random() > 0.7) { headers['X-Requested-With'] = 'XMLHttpRequest'; } if (Math.random() > 0.6) { headers['Upgrade-Insecure-Requests'] = '1'; } // Add some random custom headers occasionally if (Math.random() > 0.8) { const customHeaders = this.getRandomCustomHeaders(); Object.assign(headers, customHeaders); } return headers; } private static getRandomCustomHeaders(): Record { const customHeaders: Record = {}; const possibleHeaders = [ { 'X-Forwarded-For': this.generateRandomIP() }, { 'X-Real-IP': this.generateRandomIP() }, { 'X-Client-IP': this.generateRandomIP() }, { 'CF-Connecting-IP': this.generateRandomIP() }, { 'X-Forwarded-Proto': Math.random() > 0.5 ? 'https' : 'http' }, { 'X-Forwarded-Host': 'example.com' }, { 'X-Originating-IP': this.generateRandomIP() }, { 'X-Remote-IP': this.generateRandomIP() }, { 'X-Remote-Addr': this.generateRandomIP() }, ]; // Add 1-3 random custom headers const numHeaders = Math.floor(Math.random() * 3) + 1; for (let i = 0; i < numHeaders; i++) { const randomHeader = this.getRandomArrayElement(possibleHeaders); Object.assign(customHeaders, randomHeader); } return customHeaders; } private static generateRandomIP(): string { return `${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}`; } private static getRandomArrayElement(array: T[]): T { return array[Math.floor(Math.random() * array.length)]; } // Specific header sets for different scenarios static getBrowserHeaders(): Record { return { Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'User-Agent': UserAgentUtil.getDesktopUserAgents()[ Math.floor( Math.random() * UserAgentUtil.getDesktopUserAgents().length, ) ], 'Accept-Language': this.getRandomArrayElement(this.ACCEPT_LANGUAGES), 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive', 'Upgrade-Insecure-Requests': '1', 'Sec-Fetch-Dest': 'document', 'Sec-Fetch-Mode': 'navigate', 'Sec-Fetch-Site': 'none', 'Cache-Control': 'max-age=0', }; } static getApiHeaders(): Record { return { Accept: 'application/json, text/plain, */*', 'User-Agent': UserAgentUtil.getRandomUserAgent(), 'Accept-Language': this.getRandomArrayElement(this.ACCEPT_LANGUAGES), 'Accept-Encoding': 'gzip, deflate, br', Connection: 'keep-alive', 'Sec-Fetch-Dest': 'empty', 'Sec-Fetch-Mode': 'cors', 'Sec-Fetch-Site': 'cross-site', 'X-Requested-With': 'XMLHttpRequest', }; } static getMobileHeaders(): Record { return { Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'User-Agent': UserAgentUtil.getMobileUserAgents()[ Math.floor(Math.random() * UserAgentUtil.getMobileUserAgents().length) ], 'Accept-Language': this.getRandomArrayElement(this.ACCEPT_LANGUAGES), 'Accept-Encoding': 'gzip, deflate', Connection: 'keep-alive', }; } }