@fanboynz/network-scanner 1.0.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,613 @@
1
+ // === Enhanced Fingerprint Protection Module ===
2
+ // This module handles advanced browser fingerprint spoofing, user agent changes,
3
+ // and comprehensive bot detection evasion techniques.
4
+
5
+ // Default values for fingerprint spoofing if not set to 'random'
6
+ const DEFAULT_PLATFORM = 'Win32';
7
+ const DEFAULT_TIMEZONE = 'America/New_York';
8
+
9
+ /**
10
+ * Generates realistic screen resolutions based on common monitor sizes
11
+ * @returns {object} Screen resolution object with width and height
12
+ */
13
+ function getRealisticScreenResolution() {
14
+ const commonResolutions = [
15
+ { width: 1920, height: 1080 }, // Full HD - most common
16
+ { width: 1366, height: 768 }, // Common laptop
17
+ { width: 1440, height: 900 }, // MacBook Air
18
+ { width: 1536, height: 864 }, // Scaled HD
19
+ { width: 1600, height: 900 }, // 16:9 widescreen
20
+ { width: 2560, height: 1440 }, // 1440p
21
+ { width: 1280, height: 720 }, // 720p
22
+ { width: 3440, height: 1440 } // Ultrawide
23
+ ];
24
+
25
+ return commonResolutions[Math.floor(Math.random() * commonResolutions.length)];
26
+ }
27
+
28
+ /**
29
+ * Generates an object with randomized but realistic browser fingerprint values.
30
+ * This is used to spoof various navigator and screen properties to make
31
+ * the headless browser instance appear more like a regular user's browser
32
+ * and bypass fingerprint-based bot detection.
33
+ *
34
+ * @returns {object} An object containing the spoofed fingerprint properties
35
+ */
36
+ function getRandomFingerprint() {
37
+ const resolution = getRealisticScreenResolution();
38
+
39
+ return {
40
+ deviceMemory: [4, 8, 16, 32][Math.floor(Math.random() * 4)],
41
+ hardwareConcurrency: [2, 4, 6, 8, 12, 16][Math.floor(Math.random() * 6)],
42
+ screen: {
43
+ width: resolution.width,
44
+ height: resolution.height,
45
+ availWidth: resolution.width,
46
+ availHeight: resolution.height - 40, // Account for taskbar
47
+ colorDepth: 24,
48
+ pixelDepth: 24
49
+ },
50
+ platform: Math.random() > 0.3 ? 'Win32' : 'MacIntel',
51
+ timezone: ['America/New_York', 'America/Los_Angeles', 'Europe/London', 'America/Chicago'][Math.floor(Math.random() * 4)],
52
+ language: ['en-US', 'en-GB', 'en-CA'][Math.floor(Math.random() * 3)],
53
+ cookieEnabled: true,
54
+ doNotTrack: Math.random() > 0.7 ? '1' : null
55
+ };
56
+ }
57
+
58
+ /**
59
+ * Enhanced user agent spoofing with latest browser versions and comprehensive stealth protection
60
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
61
+ * @param {object} siteConfig - The site configuration object
62
+ * @param {boolean} forceDebug - Whether debug logging is enabled
63
+ * @param {string} currentUrl - The current URL being processed (for logging)
64
+ * @returns {Promise<void>}
65
+ */
66
+ async function applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl) {
67
+ if (!siteConfig.userAgent) return;
68
+
69
+ if (forceDebug) console.log(`[debug] Enhanced userAgent spoofing enabled for ${currentUrl}: ${siteConfig.userAgent}`);
70
+
71
+ // Updated user agents with latest browser versions
72
+ const userAgents = {
73
+ chrome: [
74
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
75
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
76
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
77
+ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
78
+ ],
79
+ firefox: [
80
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:133.0) Gecko/20100101 Firefox/133.0",
81
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:133.0) Gecko/20100101 Firefox/133.0",
82
+ "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0"
83
+ ],
84
+ safari: [
85
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.2 Safari/605.1.15",
86
+ "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.6 Safari/605.1.15"
87
+ ]
88
+ };
89
+
90
+ const selectedUserAgents = userAgents[siteConfig.userAgent.toLowerCase()];
91
+ const ua = selectedUserAgents ? selectedUserAgents[Math.floor(Math.random() * selectedUserAgents.length)] : null;
92
+
93
+ if (ua) {
94
+ await page.setUserAgent(ua);
95
+
96
+ // Apply comprehensive stealth protection when userAgent is set
97
+ if (forceDebug) console.log(`[debug] Applying enhanced stealth protection for ${currentUrl}`);
98
+
99
+ try {
100
+ await page.evaluateOnNewDocument((userAgent) => {
101
+ // 1. Enhanced webdriver removal with descriptor manipulation
102
+ delete navigator.webdriver;
103
+ Object.defineProperty(navigator, 'webdriver', {
104
+ get: () => undefined,
105
+ configurable: false,
106
+ enumerable: false
107
+ });
108
+
109
+ // 2. Enhanced automation detection removal
110
+ const automationProps = [
111
+ 'callPhantom', '_phantom', '__nightmare', '_selenium',
112
+ '__selenium_unwrapped', '__webdriver_evaluate', '__driver_evaluate',
113
+ '__webdriver_script_function', '__webdriver_script_func',
114
+ '__webdriver_script_fn', '__fxdriver_evaluate', '__driver_unwrapped',
115
+ '__webdriver_unwrapped', '__selenium_evaluate', '__fxdriver_unwrapped',
116
+ 'spawn', 'emit', 'Buffer', '__webdriver_script_func', 'domAutomation',
117
+ 'domAutomationController', '__lastWatirAlert', '__lastWatirConfirm',
118
+ '__lastWatirPrompt', '_Selenium_IDE_Recorder', '_selenium', 'calledSelenium',
119
+ '__webdriver_script_function', '__webdriver_script_func'
120
+ ];
121
+
122
+ automationProps.forEach(prop => {
123
+ delete window[prop];
124
+ delete navigator[prop];
125
+ Object.defineProperty(window, prop, {
126
+ get: () => undefined,
127
+ configurable: false,
128
+ enumerable: false
129
+ });
130
+ });
131
+
132
+ // 3. Enhanced Chrome runtime simulation
133
+ if (!window.chrome || !window.chrome.runtime) {
134
+ window.chrome = {
135
+ runtime: {
136
+ onConnect: { addListener: () => {}, removeListener: () => {} },
137
+ onMessage: { addListener: () => {}, removeListener: () => {} },
138
+ sendMessage: () => {},
139
+ connect: () => ({
140
+ onMessage: { addListener: () => {}, removeListener: () => {} },
141
+ postMessage: () => {},
142
+ disconnect: () => {}
143
+ }),
144
+ getManifest: () => ({
145
+ name: "Chrome",
146
+ version: "131.0.0.0"
147
+ }),
148
+ getURL: (path) => `chrome-extension://invalid/${path}`,
149
+ id: undefined
150
+ },
151
+ loadTimes: () => ({
152
+ commitLoadTime: performance.now() - Math.random() * 1000,
153
+ connectionInfo: 'http/1.1',
154
+ finishDocumentLoadTime: performance.now() - Math.random() * 500,
155
+ finishLoadTime: performance.now() - Math.random() * 100,
156
+ firstPaintAfterLoadTime: performance.now() - Math.random() * 50,
157
+ firstPaintTime: performance.now() - Math.random() * 200,
158
+ navigationType: 'Navigation',
159
+ npnNegotiatedProtocol: 'unknown',
160
+ requestTime: performance.now() - Math.random() * 2000,
161
+ startLoadTime: performance.now() - Math.random() * 1500,
162
+ wasAlternateProtocolAvailable: false,
163
+ wasFetchedViaSpdy: false,
164
+ wasNpnNegotiated: false
165
+ }),
166
+ csi: () => ({
167
+ onloadT: Date.now(),
168
+ pageT: Math.random() * 1000,
169
+ startE: Date.now() - Math.random() * 2000,
170
+ tran: Math.floor(Math.random() * 20)
171
+ }),
172
+ app: {
173
+ isInstalled: false,
174
+ InstallState: { DISABLED: 'disabled', INSTALLED: 'installed', NOT_INSTALLED: 'not_installed' },
175
+ RunningState: { CANNOT_RUN: 'cannot_run', READY_TO_RUN: 'ready_to_run', RUNNING: 'running' }
176
+ }
177
+ };
178
+ }
179
+
180
+ // 4. Realistic plugins based on user agent
181
+ const isChrome = userAgent.includes('Chrome');
182
+ const isFirefox = userAgent.includes('Firefox');
183
+ const isSafari = userAgent.includes('Safari') && !userAgent.includes('Chrome');
184
+
185
+ let plugins = [];
186
+ if (isChrome) {
187
+ plugins = [
188
+ { name: 'Chrome PDF Plugin', length: 1, description: 'Portable Document Format', filename: 'internal-pdf-viewer' },
189
+ { name: 'Chrome PDF Viewer', length: 1, description: 'PDF Viewer', filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai' },
190
+ { name: 'Native Client', length: 2, description: 'Native Client Executable', filename: 'internal-nacl-plugin' }
191
+ ];
192
+ } else if (isFirefox) {
193
+ plugins = [
194
+ { name: 'PDF.js', length: 2, description: 'Portable Document Format', filename: 'internal-pdf-js' }
195
+ ];
196
+ } else if (isSafari) {
197
+ plugins = [
198
+ { name: 'WebKit built-in PDF', length: 1, description: 'Portable Document Format', filename: 'internal-pdf-viewer' }
199
+ ];
200
+ }
201
+
202
+ Object.defineProperty(navigator, 'plugins', {
203
+ get: () => plugins,
204
+ configurable: true
205
+ });
206
+
207
+ // 5. Enhanced language spoofing
208
+ const languages = ['en-US', 'en'];
209
+ Object.defineProperty(navigator, 'languages', {
210
+ get: () => languages,
211
+ configurable: true
212
+ });
213
+ Object.defineProperty(navigator, 'language', {
214
+ get: () => languages[0],
215
+ configurable: true
216
+ });
217
+
218
+ // 6. Vendor and product info based on user agent
219
+ let vendor = 'Google Inc.';
220
+ let product = 'Gecko';
221
+
222
+ if (isFirefox) {
223
+ vendor = '';
224
+ product = 'Gecko';
225
+ } else if (isSafari) {
226
+ vendor = 'Apple Computer, Inc.';
227
+ product = 'Gecko';
228
+ }
229
+
230
+ Object.defineProperty(navigator, 'vendor', {
231
+ get: () => vendor,
232
+ configurable: true
233
+ });
234
+ Object.defineProperty(navigator, 'product', {
235
+ get: () => product,
236
+ configurable: true
237
+ });
238
+
239
+ // 7. Add realistic mimeTypes
240
+ Object.defineProperty(navigator, 'mimeTypes', {
241
+ get: () => {
242
+ if (isChrome) {
243
+ return [
244
+ { type: 'application/pdf', description: 'Portable Document Format', suffixes: 'pdf', enabledPlugin: plugins[0] },
245
+ { type: 'application/x-google-chrome-pdf', description: 'Portable Document Format', suffixes: 'pdf', enabledPlugin: plugins[1] },
246
+ { type: 'application/x-nacl', description: 'Native Client Executable', suffixes: '', enabledPlugin: plugins[2] }
247
+ ];
248
+ }
249
+ return [];
250
+ },
251
+ configurable: true
252
+ });
253
+
254
+ // 8. Enhanced permission API spoofing
255
+ if (navigator.permissions && navigator.permissions.query) {
256
+ const originalQuery = navigator.permissions.query;
257
+ navigator.permissions.query = function(parameters) {
258
+ const granted = ['camera', 'microphone', 'notifications'];
259
+ const denied = ['midi', 'push', 'speaker'];
260
+ const prompt = ['geolocation'];
261
+
262
+ if (granted.includes(parameters.name)) {
263
+ return Promise.resolve({ state: 'granted', onchange: null });
264
+ } else if (denied.includes(parameters.name)) {
265
+ return Promise.resolve({ state: 'denied', onchange: null });
266
+ } else if (prompt.includes(parameters.name)) {
267
+ return Promise.resolve({ state: 'prompt', onchange: null });
268
+ }
269
+ return originalQuery.apply(this, arguments);
270
+ };
271
+ }
272
+
273
+ // 9. Spoof iframe contentWindow access (common detection method)
274
+ const originalContentWindow = Object.getOwnPropertyDescriptor(HTMLIFrameElement.prototype, 'contentWindow');
275
+ if (originalContentWindow) {
276
+ Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
277
+ get: function() {
278
+ const win = originalContentWindow.get.call(this);
279
+ if (win) {
280
+ // Remove automation properties from iframe windows too
281
+ automationProps.forEach(prop => {
282
+ try {
283
+ delete win[prop];
284
+ Object.defineProperty(win, prop, {
285
+ get: () => undefined,
286
+ configurable: false,
287
+ enumerable: false
288
+ });
289
+ } catch(e) {}
290
+ });
291
+ }
292
+ return win;
293
+ },
294
+ configurable: true
295
+ });
296
+ }
297
+
298
+ // 10. Enhanced connection information spoofing
299
+ if (navigator.connection) {
300
+ Object.defineProperties(navigator.connection, {
301
+ rtt: { get: () => Math.floor(Math.random() * 100) + 50, configurable: true },
302
+ downlink: { get: () => Math.random() * 10 + 1, configurable: true },
303
+ effectiveType: { get: () => '4g', configurable: true },
304
+ saveData: { get: () => false, configurable: true }
305
+ });
306
+ }
307
+
308
+ // 11. Spoof WebGL fingerprinting
309
+ const getParameter = WebGLRenderingContext.prototype.getParameter;
310
+ WebGLRenderingContext.prototype.getParameter = function(parameter) {
311
+ if (parameter === 37445) { // UNMASKED_VENDOR_WEBGL
312
+ return 'Intel Inc.';
313
+ }
314
+ if (parameter === 37446) { // UNMASKED_RENDERER_WEBGL
315
+ return 'Intel Iris OpenGL Engine';
316
+ }
317
+ return getParameter.call(this, parameter);
318
+ };
319
+
320
+ // 12. Spoof canvas fingerprinting with subtle noise
321
+ const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
322
+ HTMLCanvasElement.prototype.toDataURL = function(...args) {
323
+ const context = this.getContext('2d');
324
+ if (context) {
325
+ // Add subtle noise to canvas to prevent fingerprinting
326
+ const imageData = context.getImageData(0, 0, this.width, this.height);
327
+ for (let i = 0; i < imageData.data.length; i += 4) {
328
+ imageData.data[i] = imageData.data[i] + Math.floor(Math.random() * 3) - 1;
329
+ }
330
+ context.putImageData(imageData, 0, 0);
331
+ }
332
+ return originalToDataURL.apply(this, args);
333
+ };
334
+
335
+ // 13. Enhanced Error.captureStackTrace to prevent detection
336
+ if (Error.captureStackTrace) {
337
+ const originalCaptureStackTrace = Error.captureStackTrace;
338
+ Error.captureStackTrace = function(targetObject, constructorOpt) {
339
+ const result = originalCaptureStackTrace.call(this, targetObject, constructorOpt);
340
+ if (targetObject.stack) {
341
+ // Remove puppeteer-related stack traces
342
+ targetObject.stack = targetObject.stack
343
+ .split('\n')
344
+ .filter(line => !line.includes('puppeteer') && !line.includes('DevTools') && !line.includes('chrome-devtools'))
345
+ .join('\n');
346
+ }
347
+ return result;
348
+ };
349
+ }
350
+
351
+ // 14. Patch toString methods to prevent detection
352
+ Function.prototype.toString = new Proxy(Function.prototype.toString, {
353
+ apply: function(target, thisArg, argumentsList) {
354
+ const result = target.apply(thisArg, argumentsList);
355
+ return result.replace(/puppeteer/gi, 'browser').replace(/headless/gi, 'chrome');
356
+ }
357
+ });
358
+
359
+ // 15. Spoof battery API if available
360
+ if (navigator.getBattery) {
361
+ const originalGetBattery = navigator.getBattery;
362
+ navigator.getBattery = function() {
363
+ return Promise.resolve({
364
+ charging: Math.random() > 0.5,
365
+ chargingTime: Math.random() > 0.5 ? Infinity : Math.random() * 3600,
366
+ dischargingTime: Math.random() * 7200,
367
+ level: Math.random() * 0.99 + 0.01,
368
+ addEventListener: () => {},
369
+ removeEventListener: () => {},
370
+ dispatchEvent: () => true
371
+ });
372
+ };
373
+ }
374
+
375
+ // 16. Add realistic timing to console methods
376
+ ['debug', 'error', 'info', 'log', 'warn'].forEach(method => {
377
+ const original = console[method];
378
+ console[method] = function(...args) {
379
+ // Add tiny random delay to mimic human-like console timing
380
+ setTimeout(() => original.apply(console, args), Math.random() * 5);
381
+ };
382
+ });
383
+
384
+ }, ua);
385
+ } catch (stealthErr) {
386
+ console.warn(`[enhanced stealth protection failed] ${currentUrl}: ${stealthErr.message}`);
387
+ }
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Enhanced Brave browser spoofing with more realistic implementation
393
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
394
+ * @param {object} siteConfig - The site configuration object
395
+ * @param {boolean} forceDebug - Whether debug logging is enabled
396
+ * @param {string} currentUrl - The current URL being processed (for logging)
397
+ * @returns {Promise<void>}
398
+ */
399
+ async function applyBraveSpoofing(page, siteConfig, forceDebug, currentUrl) {
400
+ if (!siteConfig.isBrave) return;
401
+
402
+ if (forceDebug) console.log(`[debug] Enhanced Brave spoofing enabled for ${currentUrl}`);
403
+
404
+ await page.evaluateOnNewDocument(() => {
405
+ // More comprehensive Brave spoofing
406
+ Object.defineProperty(navigator, 'brave', {
407
+ get: () => ({
408
+ isBrave: () => Promise.resolve(true),
409
+ setBadge: () => {},
410
+ clearBadge: () => {},
411
+ getAdBlockEnabled: () => Promise.resolve(true),
412
+ getShieldsEnabled: () => Promise.resolve(true)
413
+ }),
414
+ configurable: true
415
+ });
416
+
417
+ // Brave-specific user agent adjustments
418
+ if (navigator.userAgent && !navigator.userAgent.includes('Brave')) {
419
+ Object.defineProperty(navigator, 'userAgent', {
420
+ get: () => navigator.userAgent.replace('Chrome/', 'Brave/').replace('Safari/537.36', 'Safari/537.36 Brave/1.60'),
421
+ configurable: true
422
+ });
423
+ }
424
+ });
425
+ }
426
+
427
+ /**
428
+ * Enhanced fingerprint protection with more realistic and varied spoofing
429
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
430
+ * @param {object} siteConfig - The site configuration object
431
+ * @param {boolean} forceDebug - Whether debug logging is enabled
432
+ * @param {string} currentUrl - The current URL being processed (for logging)
433
+ * @returns {Promise<void>}
434
+ */
435
+ async function applyFingerprintProtection(page, siteConfig, forceDebug, currentUrl) {
436
+ const fingerprintSetting = siteConfig.fingerprint_protection;
437
+ if (!fingerprintSetting) return;
438
+
439
+ if (forceDebug) console.log(`[debug] Enhanced fingerprint_protection enabled for ${currentUrl}`);
440
+
441
+ const spoof = fingerprintSetting === 'random' ? getRandomFingerprint() : {
442
+ deviceMemory: 8,
443
+ hardwareConcurrency: 4,
444
+ screen: { width: 1920, height: 1080, availWidth: 1920, availHeight: 1040, colorDepth: 24, pixelDepth: 24 },
445
+ platform: DEFAULT_PLATFORM,
446
+ timezone: DEFAULT_TIMEZONE,
447
+ language: 'en-US',
448
+ cookieEnabled: true,
449
+ doNotTrack: null
450
+ };
451
+
452
+ try {
453
+ await page.evaluateOnNewDocument(({ spoof }) => {
454
+ // Enhanced property spoofing with more realistic values
455
+ Object.defineProperty(navigator, 'deviceMemory', {
456
+ get: () => spoof.deviceMemory,
457
+ configurable: true,
458
+ enumerable: true
459
+ });
460
+
461
+ Object.defineProperty(navigator, 'hardwareConcurrency', {
462
+ get: () => spoof.hardwareConcurrency,
463
+ configurable: true,
464
+ enumerable: true
465
+ });
466
+
467
+ // Enhanced screen properties
468
+ ['width', 'height', 'availWidth', 'availHeight', 'colorDepth', 'pixelDepth'].forEach(prop => {
469
+ if (spoof.screen[prop] !== undefined) {
470
+ Object.defineProperty(window.screen, prop, {
471
+ get: () => spoof.screen[prop],
472
+ configurable: true,
473
+ enumerable: true
474
+ });
475
+ }
476
+ });
477
+
478
+ Object.defineProperty(navigator, 'platform', {
479
+ get: () => spoof.platform,
480
+ configurable: true,
481
+ enumerable: true
482
+ });
483
+
484
+ // Enhanced timezone spoofing
485
+ const originalDateTimeFormat = Intl.DateTimeFormat;
486
+ Intl.DateTimeFormat = function(...args) {
487
+ const instance = new originalDateTimeFormat(...args);
488
+ const originalResolvedOptions = instance.resolvedOptions;
489
+ instance.resolvedOptions = function() {
490
+ const options = originalResolvedOptions.call(this);
491
+ options.timeZone = spoof.timezone;
492
+ return options;
493
+ };
494
+ return instance;
495
+ };
496
+
497
+ // Spoof Date.getTimezoneOffset
498
+ const originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
499
+ Date.prototype.getTimezoneOffset = function() {
500
+ // Return offset for spoofed timezone
501
+ const timezoneOffsets = {
502
+ 'America/New_York': 300, // EST offset
503
+ 'America/Los_Angeles': 480, // PST offset
504
+ 'Europe/London': 0, // GMT offset
505
+ 'America/Chicago': 360 // CST offset
506
+ };
507
+ return timezoneOffsets[spoof.timezone] || originalGetTimezoneOffset.call(this);
508
+ };
509
+
510
+ // Enhanced cookie and DNT spoofing
511
+ if (spoof.cookieEnabled !== undefined) {
512
+ Object.defineProperty(navigator, 'cookieEnabled', {
513
+ get: () => spoof.cookieEnabled,
514
+ configurable: true
515
+ });
516
+ }
517
+
518
+ if (spoof.doNotTrack !== undefined) {
519
+ Object.defineProperty(navigator, 'doNotTrack', {
520
+ get: () => spoof.doNotTrack,
521
+ configurable: true
522
+ });
523
+ }
524
+
525
+ }, { spoof });
526
+ } catch (err) {
527
+ console.warn(`[enhanced fingerprint spoof failed] ${currentUrl}: ${err.message}`);
528
+ }
529
+ }
530
+
531
+ /**
532
+ * Add mouse movement simulation to appear more human-like
533
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
534
+ * @param {boolean} forceDebug - Whether debug logging is enabled
535
+ * @returns {Promise<void>}
536
+ */
537
+ async function simulateHumanBehavior(page, forceDebug) {
538
+ try {
539
+ await page.evaluateOnNewDocument(() => {
540
+ // Simulate human-like mouse movements
541
+ let mouseX = Math.random() * window.innerWidth;
542
+ let mouseY = Math.random() * window.innerHeight;
543
+
544
+ const moveInterval = setInterval(() => {
545
+ mouseX += (Math.random() - 0.5) * 20;
546
+ mouseY += (Math.random() - 0.5) * 20;
547
+
548
+ mouseX = Math.max(0, Math.min(window.innerWidth, mouseX));
549
+ mouseY = Math.max(0, Math.min(window.innerHeight, mouseY));
550
+
551
+ document.dispatchEvent(new MouseEvent('mousemove', {
552
+ clientX: mouseX,
553
+ clientY: mouseY,
554
+ bubbles: true
555
+ }));
556
+ }, 1000 + Math.random() * 2000);
557
+
558
+ // Simulate occasional clicks and scrolls
559
+ setTimeout(() => {
560
+ if (Math.random() > 0.7) {
561
+ document.dispatchEvent(new MouseEvent('click', {
562
+ clientX: mouseX,
563
+ clientY: mouseY,
564
+ bubbles: true
565
+ }));
566
+ }
567
+
568
+ // Simulate scroll events
569
+ if (Math.random() > 0.8) {
570
+ window.scrollBy(0, Math.random() * 100 - 50);
571
+ }
572
+ }, 5000 + Math.random() * 10000);
573
+
574
+ // Stop simulation after 30 seconds to avoid detection
575
+ setTimeout(() => {
576
+ clearInterval(moveInterval);
577
+ }, 30000);
578
+ });
579
+ } catch (err) {
580
+ if (forceDebug) console.log(`[debug] Human behavior simulation failed: ${err.message}`);
581
+ }
582
+ }
583
+
584
+ /**
585
+ * Enhanced main function that applies all fingerprint spoofing techniques
586
+ * @param {import('puppeteer').Page} page - The Puppeteer page instance
587
+ * @param {object} siteConfig - The site configuration object
588
+ * @param {boolean} forceDebug - Whether debug logging is enabled
589
+ * @param {string} currentUrl - The current URL being processed (for logging)
590
+ * @returns {Promise<void>}
591
+ */
592
+ async function applyAllFingerprintSpoofing(page, siteConfig, forceDebug, currentUrl) {
593
+ await applyUserAgentSpoofing(page, siteConfig, forceDebug, currentUrl);
594
+ await applyBraveSpoofing(page, siteConfig, forceDebug, currentUrl);
595
+ await applyFingerprintProtection(page, siteConfig, forceDebug, currentUrl);
596
+
597
+ // Add human behavior simulation if user agent spoofing is enabled
598
+ if (siteConfig.userAgent) {
599
+ await simulateHumanBehavior(page, forceDebug);
600
+ }
601
+ }
602
+
603
+ module.exports = {
604
+ getRandomFingerprint,
605
+ getRealisticScreenResolution,
606
+ applyUserAgentSpoofing,
607
+ applyBraveSpoofing,
608
+ applyFingerprintProtection,
609
+ applyAllFingerprintSpoofing,
610
+ simulateHumanBehavior,
611
+ DEFAULT_PLATFORM,
612
+ DEFAULT_TIMEZONE
613
+ };