@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.
- package/.github/workflows/npm-publish.yml +33 -0
- package/JSONMANUAL.md +121 -0
- package/LICENSE +674 -0
- package/README.md +357 -0
- package/config.json +74 -0
- package/lib/browserexit.js +522 -0
- package/lib/browserhealth.js +308 -0
- package/lib/cloudflare.js +660 -0
- package/lib/colorize.js +168 -0
- package/lib/compare.js +159 -0
- package/lib/compress.js +129 -0
- package/lib/fingerprint.js +613 -0
- package/lib/flowproxy.js +274 -0
- package/lib/grep.js +348 -0
- package/lib/ignore_similar.js +237 -0
- package/lib/nettools.js +1200 -0
- package/lib/output.js +633 -0
- package/lib/redirect.js +384 -0
- package/lib/searchstring.js +561 -0
- package/lib/validate_rules.js +1107 -0
- package/nwss.1 +824 -0
- package/nwss.js +2488 -0
- package/package.json +45 -0
- package/regex-samples.md +27 -0
- package/scanner-script-org.js +588 -0
|
@@ -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
|
+
};
|