crawlforge-mcp-server 3.0.0
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/CLAUDE.md +315 -0
- package/LICENSE +21 -0
- package/README.md +181 -0
- package/package.json +115 -0
- package/server.js +1963 -0
- package/setup.js +112 -0
- package/src/constants/config.js +615 -0
- package/src/core/ActionExecutor.js +1104 -0
- package/src/core/AlertNotificationSystem.js +601 -0
- package/src/core/AuthManager.js +315 -0
- package/src/core/ChangeTracker.js +2306 -0
- package/src/core/JobManager.js +687 -0
- package/src/core/LLMsTxtAnalyzer.js +753 -0
- package/src/core/LocalizationManager.js +1615 -0
- package/src/core/PerformanceManager.js +828 -0
- package/src/core/ResearchOrchestrator.js +1327 -0
- package/src/core/SnapshotManager.js +1037 -0
- package/src/core/StealthBrowserManager.js +1795 -0
- package/src/core/WebhookDispatcher.js +745 -0
- package/src/core/analysis/ContentAnalyzer.js +749 -0
- package/src/core/analysis/LinkAnalyzer.js +972 -0
- package/src/core/cache/CacheManager.js +821 -0
- package/src/core/connections/ConnectionPool.js +553 -0
- package/src/core/crawlers/BFSCrawler.js +845 -0
- package/src/core/integrations/PerformanceIntegration.js +377 -0
- package/src/core/llm/AnthropicProvider.js +135 -0
- package/src/core/llm/LLMManager.js +415 -0
- package/src/core/llm/LLMProvider.js +97 -0
- package/src/core/llm/OpenAIProvider.js +127 -0
- package/src/core/processing/BrowserProcessor.js +986 -0
- package/src/core/processing/ContentProcessor.js +505 -0
- package/src/core/processing/PDFProcessor.js +448 -0
- package/src/core/processing/StreamProcessor.js +673 -0
- package/src/core/queue/QueueManager.js +98 -0
- package/src/core/workers/WorkerPool.js +585 -0
- package/src/core/workers/worker.js +743 -0
- package/src/monitoring/healthCheck.js +600 -0
- package/src/monitoring/metrics.js +761 -0
- package/src/optimization/wave3-optimizations.js +932 -0
- package/src/security/security-patches.js +120 -0
- package/src/security/security-tests.js +355 -0
- package/src/security/wave3-security.js +652 -0
- package/src/tools/advanced/BatchScrapeTool.js +1089 -0
- package/src/tools/advanced/ScrapeWithActionsTool.js +669 -0
- package/src/tools/crawl/crawlDeep.js +449 -0
- package/src/tools/crawl/mapSite.js +400 -0
- package/src/tools/extract/analyzeContent.js +624 -0
- package/src/tools/extract/extractContent.js +329 -0
- package/src/tools/extract/processDocument.js +503 -0
- package/src/tools/extract/summarizeContent.js +376 -0
- package/src/tools/llmstxt/generateLLMsTxt.js +570 -0
- package/src/tools/research/deepResearch.js +706 -0
- package/src/tools/search/adapters/duckduckgoSearch.js +398 -0
- package/src/tools/search/adapters/googleSearch.js +236 -0
- package/src/tools/search/adapters/searchProviderFactory.js +96 -0
- package/src/tools/search/queryExpander.js +543 -0
- package/src/tools/search/ranking/ResultDeduplicator.js +676 -0
- package/src/tools/search/ranking/ResultRanker.js +497 -0
- package/src/tools/search/searchWeb.js +482 -0
- package/src/tools/tracking/trackChanges.js +1355 -0
- package/src/utils/CircuitBreaker.js +515 -0
- package/src/utils/ErrorHandlingConfig.js +342 -0
- package/src/utils/HumanBehaviorSimulator.js +569 -0
- package/src/utils/Logger.js +568 -0
- package/src/utils/MemoryMonitor.js +173 -0
- package/src/utils/RetryManager.js +386 -0
- package/src/utils/contentUtils.js +588 -0
- package/src/utils/domainFilter.js +612 -0
- package/src/utils/inputValidation.js +766 -0
- package/src/utils/rateLimiter.js +196 -0
- package/src/utils/robotsChecker.js +91 -0
- package/src/utils/securityMiddleware.js +416 -0
- package/src/utils/sitemapParser.js +678 -0
- package/src/utils/ssrfProtection.js +640 -0
- package/src/utils/urlNormalizer.js +168 -0
|
@@ -0,0 +1,1795 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StealthBrowserManager - Comprehensive Anti-detection browser management
|
|
3
|
+
* Phase 2.2 Features:
|
|
4
|
+
* - Advanced browser fingerprint randomization (User Agent, Canvas, WebGL, Screen, Plugins)
|
|
5
|
+
* - Human behavior simulation (Bezier mouse movements, realistic typing, scroll patterns)
|
|
6
|
+
* - Anti-detection features (CloudFlare bypass, reCAPTCHA handling, proxy rotation)
|
|
7
|
+
* - WebRTC leak prevention and automation indicator hiding
|
|
8
|
+
* - Stealth mode robust enough to bypass common bot detection services
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { chromium } from 'playwright';
|
|
12
|
+
import { z } from 'zod';
|
|
13
|
+
import crypto from 'crypto';
|
|
14
|
+
import HumanBehaviorSimulator from '../utils/HumanBehaviorSimulator.js';
|
|
15
|
+
|
|
16
|
+
const StealthConfigSchema = z.object({
|
|
17
|
+
level: z.enum(['basic', 'medium', 'advanced']).default('medium'),
|
|
18
|
+
randomizeFingerprint: z.boolean().default(true),
|
|
19
|
+
hideWebDriver: z.boolean().default(true),
|
|
20
|
+
blockWebRTC: z.boolean().default(true),
|
|
21
|
+
spoofTimezone: z.boolean().default(true),
|
|
22
|
+
randomizeHeaders: z.boolean().default(true),
|
|
23
|
+
useRandomUserAgent: z.boolean().default(true),
|
|
24
|
+
simulateHumanBehavior: z.boolean().default(true),
|
|
25
|
+
customUserAgent: z.string().optional(),
|
|
26
|
+
customViewport: z.object({
|
|
27
|
+
width: z.number().min(800).max(1920),
|
|
28
|
+
height: z.number().min(600).max(1080)
|
|
29
|
+
}).optional(),
|
|
30
|
+
locale: z.string().default('en-US'),
|
|
31
|
+
timezone: z.string().optional(),
|
|
32
|
+
webRTCPublicIP: z.string().optional(),
|
|
33
|
+
webRTCLocalIPs: z.array(z.string()).optional(),
|
|
34
|
+
|
|
35
|
+
// Advanced stealth options
|
|
36
|
+
proxyRotation: z.object({
|
|
37
|
+
enabled: z.boolean().default(false),
|
|
38
|
+
proxies: z.array(z.string()).optional(),
|
|
39
|
+
rotationInterval: z.number().default(300000) // 5 minutes
|
|
40
|
+
}).optional(),
|
|
41
|
+
|
|
42
|
+
antiDetection: z.object({
|
|
43
|
+
cloudflareBypass: z.boolean().default(true),
|
|
44
|
+
recaptchaHandling: z.boolean().default(true),
|
|
45
|
+
hideAutomation: z.boolean().default(true),
|
|
46
|
+
spoofMediaDevices: z.boolean().default(true),
|
|
47
|
+
spoofBatteryAPI: z.boolean().default(true)
|
|
48
|
+
}).optional(),
|
|
49
|
+
|
|
50
|
+
fingerprinting: z.object({
|
|
51
|
+
canvasNoise: z.boolean().default(true),
|
|
52
|
+
webglSpoofing: z.boolean().default(true),
|
|
53
|
+
audioContextSpoofing: z.boolean().default(true),
|
|
54
|
+
fontSpoofing: z.boolean().default(true),
|
|
55
|
+
hardwareSpoofing: z.boolean().default(true)
|
|
56
|
+
}).optional()
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export class StealthBrowserManager {
|
|
60
|
+
constructor(options = {}) {
|
|
61
|
+
this.browser = null;
|
|
62
|
+
this.contexts = new Map();
|
|
63
|
+
this.fingerprints = new Map();
|
|
64
|
+
|
|
65
|
+
// Enhanced stealth components
|
|
66
|
+
this.humanBehaviorSimulator = null;
|
|
67
|
+
this.proxyManager = {
|
|
68
|
+
currentProxy: null,
|
|
69
|
+
proxyIndex: 0,
|
|
70
|
+
lastRotation: 0,
|
|
71
|
+
activeProxies: []
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
// Detection bypass cache
|
|
75
|
+
this.bypassCache = new Map();
|
|
76
|
+
|
|
77
|
+
// Canvas fingerprint cache to maintain consistency
|
|
78
|
+
this.canvasCache = new Map();
|
|
79
|
+
|
|
80
|
+
// Performance monitoring
|
|
81
|
+
this.performanceMetrics = {
|
|
82
|
+
detectionAttempts: 0,
|
|
83
|
+
successfulBypasses: 0,
|
|
84
|
+
failedBypasses: 0,
|
|
85
|
+
averageResponseTime: 0
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Default stealth configuration
|
|
89
|
+
this.defaultConfig = {
|
|
90
|
+
level: 'medium',
|
|
91
|
+
randomizeFingerprint: true,
|
|
92
|
+
hideWebDriver: true,
|
|
93
|
+
blockWebRTC: true,
|
|
94
|
+
spoofTimezone: true,
|
|
95
|
+
randomizeHeaders: true,
|
|
96
|
+
useRandomUserAgent: true,
|
|
97
|
+
simulateHumanBehavior: true,
|
|
98
|
+
locale: 'en-US',
|
|
99
|
+
proxyRotation: { enabled: false },
|
|
100
|
+
antiDetection: {
|
|
101
|
+
cloudflareBypass: true,
|
|
102
|
+
recaptchaHandling: true,
|
|
103
|
+
hideAutomation: true,
|
|
104
|
+
spoofMediaDevices: true,
|
|
105
|
+
spoofBatteryAPI: true
|
|
106
|
+
},
|
|
107
|
+
fingerprinting: {
|
|
108
|
+
canvasNoise: true,
|
|
109
|
+
webglSpoofing: true,
|
|
110
|
+
audioContextSpoofing: true,
|
|
111
|
+
fontSpoofing: true,
|
|
112
|
+
hardwareSpoofing: true
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Enhanced User agent pools with realistic patterns
|
|
117
|
+
this.userAgentPools = {
|
|
118
|
+
chrome: {
|
|
119
|
+
windows: [
|
|
120
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
121
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
122
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36',
|
|
123
|
+
'Mozilla/5.0 (Windows NT 11.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
|
|
124
|
+
],
|
|
125
|
+
macos: [
|
|
126
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
127
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
|
|
128
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 13_6_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36'
|
|
129
|
+
],
|
|
130
|
+
linux: [
|
|
131
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
|
|
132
|
+
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
|
|
133
|
+
]
|
|
134
|
+
},
|
|
135
|
+
firefox: {
|
|
136
|
+
windows: [
|
|
137
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:122.0) Gecko/20100101 Firefox/122.0',
|
|
138
|
+
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0'
|
|
139
|
+
],
|
|
140
|
+
macos: [
|
|
141
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0',
|
|
142
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:121.0) Gecko/20100101 Firefox/121.0'
|
|
143
|
+
],
|
|
144
|
+
linux: [
|
|
145
|
+
'Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0',
|
|
146
|
+
'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0'
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
safari: {
|
|
150
|
+
macos: [
|
|
151
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Safari/605.1.15',
|
|
152
|
+
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15'
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Operating system distributions for realistic user agent selection
|
|
158
|
+
this.osDistribution = {
|
|
159
|
+
windows: 0.75,
|
|
160
|
+
macos: 0.15,
|
|
161
|
+
linux: 0.10
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Browser market share for realistic selection
|
|
165
|
+
this.browserDistribution = {
|
|
166
|
+
chrome: 0.65,
|
|
167
|
+
firefox: 0.20,
|
|
168
|
+
safari: 0.15
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// Realistic viewport sizes with market distribution
|
|
172
|
+
this.viewportSizes = [
|
|
173
|
+
{ width: 1920, height: 1080, weight: 0.25 }, // Most common
|
|
174
|
+
{ width: 1366, height: 768, weight: 0.20 }, // Second most common
|
|
175
|
+
{ width: 1536, height: 864, weight: 0.15 },
|
|
176
|
+
{ width: 1440, height: 900, weight: 0.12 },
|
|
177
|
+
{ width: 1280, height: 720, weight: 0.10 },
|
|
178
|
+
{ width: 1600, height: 900, weight: 0.08 },
|
|
179
|
+
{ width: 1024, height: 768, weight: 0.05 }, // Legacy but still used
|
|
180
|
+
{ width: 2560, height: 1440, weight: 0.03 }, // High-res displays
|
|
181
|
+
{ width: 3840, height: 2160, weight: 0.02 } // 4K displays
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
// Mobile viewport sizes for mobile emulation
|
|
185
|
+
this.mobileViewportSizes = [
|
|
186
|
+
{ width: 375, height: 667, weight: 0.25 }, // iPhone SE/8
|
|
187
|
+
{ width: 414, height: 896, weight: 0.20 }, // iPhone 11/XR
|
|
188
|
+
{ width: 390, height: 844, weight: 0.15 }, // iPhone 12/13/14
|
|
189
|
+
{ width: 360, height: 640, weight: 0.15 }, // Android common
|
|
190
|
+
{ width: 412, height: 915, weight: 0.10 }, // Pixel
|
|
191
|
+
{ width: 393, height: 851, weight: 0.10 }, // Pixel 7
|
|
192
|
+
{ width: 320, height: 568, weight: 0.05 } // iPhone 5s (legacy)
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
// Timezone options
|
|
196
|
+
this.timezones = [
|
|
197
|
+
'America/New_York',
|
|
198
|
+
'America/Los_Angeles',
|
|
199
|
+
'America/Chicago',
|
|
200
|
+
'America/Denver',
|
|
201
|
+
'Europe/London',
|
|
202
|
+
'Europe/Berlin',
|
|
203
|
+
'Europe/Paris',
|
|
204
|
+
'Europe/Madrid',
|
|
205
|
+
'Asia/Tokyo',
|
|
206
|
+
'Asia/Shanghai',
|
|
207
|
+
'Asia/Seoul',
|
|
208
|
+
'Australia/Sydney',
|
|
209
|
+
'Australia/Melbourne'
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
// WebRTC leak prevention IPs
|
|
213
|
+
this.webRTCIPs = [
|
|
214
|
+
'192.168.1.1',
|
|
215
|
+
'192.168.0.1',
|
|
216
|
+
'10.0.0.1',
|
|
217
|
+
'172.16.0.1',
|
|
218
|
+
'172.16.1.1'
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Launch stealth browser with anti-detection configurations
|
|
224
|
+
*/
|
|
225
|
+
async launchStealthBrowser(config = {}) {
|
|
226
|
+
if (this.browser) {
|
|
227
|
+
return this.browser;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const validatedConfig = StealthConfigSchema.parse({ ...this.defaultConfig, ...config });
|
|
231
|
+
|
|
232
|
+
// Base browser args for stealth
|
|
233
|
+
const stealthArgs = [
|
|
234
|
+
'--no-sandbox',
|
|
235
|
+
'--disable-dev-shm-usage',
|
|
236
|
+
'--disable-blink-features=AutomationControlled',
|
|
237
|
+
'--disable-web-security',
|
|
238
|
+
'--disable-features=VizDisplayCompositor',
|
|
239
|
+
'--disable-extensions',
|
|
240
|
+
'--disable-plugins',
|
|
241
|
+
'--disable-background-timer-throttling',
|
|
242
|
+
'--disable-backgrounding-occluded-windows',
|
|
243
|
+
'--disable-renderer-backgrounding',
|
|
244
|
+
'--disable-field-trial-config',
|
|
245
|
+
'--disable-back-forward-cache',
|
|
246
|
+
'--disable-hang-monitor',
|
|
247
|
+
'--disable-prompt-on-repost',
|
|
248
|
+
'--disable-sync',
|
|
249
|
+
'--disable-translate',
|
|
250
|
+
'--metrics-recording-only',
|
|
251
|
+
'--no-first-run',
|
|
252
|
+
'--safebrowsing-disable-auto-update',
|
|
253
|
+
'--password-store=basic',
|
|
254
|
+
'--use-mock-keychain',
|
|
255
|
+
|
|
256
|
+
// Additional stealth arguments
|
|
257
|
+
'--disable-default-apps',
|
|
258
|
+
'--disable-component-extensions-with-background-pages',
|
|
259
|
+
'--disable-background-networking',
|
|
260
|
+
'--disable-component-update',
|
|
261
|
+
'--disable-client-side-phishing-detection',
|
|
262
|
+
'--disable-domain-reliability',
|
|
263
|
+
'--disable-ipc-flooding-protection',
|
|
264
|
+
'--no-default-browser-check',
|
|
265
|
+
'--no-pings',
|
|
266
|
+
'--disable-notifications'
|
|
267
|
+
];
|
|
268
|
+
|
|
269
|
+
// Advanced stealth args based on level
|
|
270
|
+
if (validatedConfig.level === 'advanced') {
|
|
271
|
+
stealthArgs.push(
|
|
272
|
+
'--disable-gpu-sandbox',
|
|
273
|
+
'--disable-popup-blocking',
|
|
274
|
+
'--disable-setuid-sandbox',
|
|
275
|
+
'--disable-site-isolation-trials',
|
|
276
|
+
'--disable-threaded-animation',
|
|
277
|
+
'--disable-threaded-scrolling',
|
|
278
|
+
'--disable-in-process-stack-traces',
|
|
279
|
+
'--disable-histogram-customizer',
|
|
280
|
+
'--disable-gl-extensions',
|
|
281
|
+
'--disable-composited-antialiasing',
|
|
282
|
+
'--disable-canvas-aa',
|
|
283
|
+
'--disable-3d-apis',
|
|
284
|
+
'--disable-accelerated-2d-canvas',
|
|
285
|
+
'--disable-accelerated-jpeg-decoding',
|
|
286
|
+
'--disable-accelerated-mjpeg-decode',
|
|
287
|
+
'--disable-app-list-dismiss-on-blur',
|
|
288
|
+
'--disable-accelerated-video-decode',
|
|
289
|
+
'--disable-logging',
|
|
290
|
+
'--silent'
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// WebRTC blocking
|
|
295
|
+
if (validatedConfig.blockWebRTC) {
|
|
296
|
+
stealthArgs.push(
|
|
297
|
+
'--disable-webrtc-hw-decoding',
|
|
298
|
+
'--disable-webrtc-hw-encoding',
|
|
299
|
+
'--disable-webrtc-multiple-routes',
|
|
300
|
+
'--disable-webrtc-hw-vp8-encoding',
|
|
301
|
+
'--enforce-webrtc-ip-permission-check'
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// Handle proxy configuration
|
|
306
|
+
const currentProxy = await this.rotateProxy(validatedConfig);
|
|
307
|
+
if (currentProxy) {
|
|
308
|
+
stealthArgs.push(`--proxy-server=${currentProxy}`);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
this.browser = await chromium.launch({
|
|
312
|
+
headless: true,
|
|
313
|
+
args: stealthArgs,
|
|
314
|
+
ignoreDefaultArgs: [
|
|
315
|
+
'--enable-blink-features=IdleDetection',
|
|
316
|
+
'--enable-automation'
|
|
317
|
+
]
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
return this.browser;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Create stealth browser context with anti-fingerprinting
|
|
325
|
+
*/
|
|
326
|
+
async createStealthContext(config = {}) {
|
|
327
|
+
const validatedConfig = StealthConfigSchema.parse({ ...this.defaultConfig, ...config });
|
|
328
|
+
|
|
329
|
+
if (!this.browser) {
|
|
330
|
+
await this.launchStealthBrowser(validatedConfig);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Generate fingerprint for this context
|
|
334
|
+
const fingerprint = this.generateAdvancedFingerprint(validatedConfig);
|
|
335
|
+
|
|
336
|
+
const contextOptions = {
|
|
337
|
+
viewport: fingerprint.viewport,
|
|
338
|
+
userAgent: fingerprint.userAgent,
|
|
339
|
+
locale: validatedConfig.locale,
|
|
340
|
+
timezoneId: fingerprint.timezone,
|
|
341
|
+
deviceScaleFactor: fingerprint.deviceScaleFactor,
|
|
342
|
+
isMobile: fingerprint.isMobile,
|
|
343
|
+
hasTouch: fingerprint.hasTouch,
|
|
344
|
+
colorScheme: fingerprint.colorScheme,
|
|
345
|
+
reducedMotion: fingerprint.reducedMotion,
|
|
346
|
+
forcedColors: fingerprint.forcedColors,
|
|
347
|
+
extraHTTPHeaders: fingerprint.headers,
|
|
348
|
+
|
|
349
|
+
// Geolocation spoofing
|
|
350
|
+
geolocation: fingerprint.geolocation,
|
|
351
|
+
permissions: ['geolocation'],
|
|
352
|
+
|
|
353
|
+
// Media spoofing
|
|
354
|
+
screen: {
|
|
355
|
+
width: fingerprint.screen.width,
|
|
356
|
+
height: fingerprint.screen.height
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
// Bypass various detections
|
|
360
|
+
bypassCSP: true,
|
|
361
|
+
javaScriptEnabled: true
|
|
362
|
+
};
|
|
363
|
+
|
|
364
|
+
const context = await this.browser.newContext(contextOptions);
|
|
365
|
+
const contextId = this.generateContextId();
|
|
366
|
+
|
|
367
|
+
// Apply stealth scripts and configurations
|
|
368
|
+
await this.applyAdvancedStealthConfigurations(context, validatedConfig, fingerprint);
|
|
369
|
+
|
|
370
|
+
this.contexts.set(contextId, { context, fingerprint, config: validatedConfig });
|
|
371
|
+
this.fingerprints.set(contextId, fingerprint);
|
|
372
|
+
|
|
373
|
+
return { context, contextId, fingerprint };
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Generate advanced browser fingerprint with enhanced randomization
|
|
378
|
+
*/
|
|
379
|
+
generateAdvancedFingerprint(config = {}) {
|
|
380
|
+
const fingerprint = {
|
|
381
|
+
userAgent: this.selectRealisticUserAgent(config),
|
|
382
|
+
viewport: config.customViewport || this.selectWeightedViewport(),
|
|
383
|
+
timezone: config.timezone || this.selectTimezone(),
|
|
384
|
+
deviceScaleFactor: this.randomFloat(1, 2, 1),
|
|
385
|
+
isMobile: Math.random() < 0.1, // 10% mobile
|
|
386
|
+
hasTouch: Math.random() < 0.15, // 15% touch
|
|
387
|
+
colorScheme: Math.random() < 0.3 ? 'dark' : 'light',
|
|
388
|
+
reducedMotion: Math.random() < 0.1 ? 'reduce' : 'no-preference',
|
|
389
|
+
forcedColors: Math.random() < 0.05 ? 'active' : 'none',
|
|
390
|
+
headers: this.generateAdvancedHeaders(config),
|
|
391
|
+
webRTC: this.generateWebRTCConfig(config),
|
|
392
|
+
canvas: this.generateAdvancedCanvasFingerprint(),
|
|
393
|
+
webGL: this.generateAdvancedWebGLFingerprint(),
|
|
394
|
+
audioContext: this.generateAudioContextFingerprint(),
|
|
395
|
+
mediaDevices: this.generateMediaDevicesFingerprint(),
|
|
396
|
+
hardware: this.generateHardwareFingerprint(),
|
|
397
|
+
fonts: this.generateAdvancedFontList(),
|
|
398
|
+
plugins: this.generateAdvancedPluginList(),
|
|
399
|
+
geolocation: this.generateRealisticGeolocation(),
|
|
400
|
+
screen: this.generateAdvancedScreenProperties(),
|
|
401
|
+
battery: this.generateBatteryFingerprint()
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
return fingerprint;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Select realistic user agent based on market distribution
|
|
409
|
+
*/
|
|
410
|
+
selectRealisticUserAgent(config) {
|
|
411
|
+
if (config.customUserAgent) {
|
|
412
|
+
return config.customUserAgent;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!config.useRandomUserAgent) {
|
|
416
|
+
return this.userAgentPools.chrome.windows[0];
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// Select OS based on distribution
|
|
420
|
+
const selectedOS = this.weightedRandom(this.osDistribution);
|
|
421
|
+
|
|
422
|
+
// Select browser based on distribution and OS compatibility
|
|
423
|
+
let availableBrowsers = { ...this.browserDistribution };
|
|
424
|
+
if (selectedOS === 'linux' && availableBrowsers.safari) {
|
|
425
|
+
delete availableBrowsers.safari;
|
|
426
|
+
// Redistribute safari's weight
|
|
427
|
+
availableBrowsers.chrome += 0.075;
|
|
428
|
+
availableBrowsers.firefox += 0.075;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const selectedBrowser = this.weightedRandom(availableBrowsers);
|
|
432
|
+
const pool = this.userAgentPools[selectedBrowser][selectedOS];
|
|
433
|
+
|
|
434
|
+
if (!pool || pool.length === 0) {
|
|
435
|
+
// Fallback to Chrome Windows
|
|
436
|
+
return this.userAgentPools.chrome.windows[0];
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return pool[Math.floor(Math.random() * pool.length)];
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Select viewport size based on weights
|
|
444
|
+
*/
|
|
445
|
+
selectWeightedViewport() {
|
|
446
|
+
return this.weightedRandomFromArray(this.viewportSizes);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Select timezone
|
|
451
|
+
*/
|
|
452
|
+
selectTimezone() {
|
|
453
|
+
return this.timezones[Math.floor(Math.random() * this.timezones.length)];
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Generate advanced HTTP headers with realistic patterns
|
|
458
|
+
*/
|
|
459
|
+
generateAdvancedHeaders(config) {
|
|
460
|
+
const headers = {
|
|
461
|
+
'Accept-Language': `${(config.locale || 'en-US').toLowerCase()},en;q=0.9`,
|
|
462
|
+
'Accept': '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',
|
|
463
|
+
'Accept-Encoding': 'gzip, deflate, br',
|
|
464
|
+
'Cache-Control': 'max-age=0',
|
|
465
|
+
'Upgrade-Insecure-Requests': '1',
|
|
466
|
+
'Sec-Fetch-Dest': 'document',
|
|
467
|
+
'Sec-Fetch-Mode': 'navigate',
|
|
468
|
+
'Sec-Fetch-Site': 'none',
|
|
469
|
+
'Sec-Fetch-User': '?1',
|
|
470
|
+
'sec-ch-ua-mobile': '?0',
|
|
471
|
+
'sec-ch-ua-platform': this.generateSecChUaPlatform()
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// Add sec-ch-ua header
|
|
475
|
+
headers['sec-ch-ua'] = this.generateSecChUaHeader();
|
|
476
|
+
|
|
477
|
+
// Randomize some headers
|
|
478
|
+
if (Math.random() < 0.25) {
|
|
479
|
+
headers['DNT'] = '1';
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (Math.random() < 0.6) {
|
|
483
|
+
headers['Connection'] = 'keep-alive';
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Add Save-Data header occasionally
|
|
487
|
+
if (Math.random() < 0.1) {
|
|
488
|
+
headers['Save-Data'] = 'on';
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
return headers;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Generate sec-ch-ua header
|
|
496
|
+
*/
|
|
497
|
+
generateSecChUaHeader() {
|
|
498
|
+
const brands = [
|
|
499
|
+
{ brand: 'Not_A Brand', version: '8' },
|
|
500
|
+
{ brand: 'Chromium', version: '120' },
|
|
501
|
+
{ brand: 'Google Chrome', version: '120' }
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
return brands
|
|
505
|
+
.map(b => `"${b.brand}";v="${b.version}"`)
|
|
506
|
+
.join(', ');
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Generate sec-ch-ua-platform header
|
|
511
|
+
*/
|
|
512
|
+
generateSecChUaPlatform() {
|
|
513
|
+
const platforms = {
|
|
514
|
+
windows: '"Windows"',
|
|
515
|
+
macos: '"macOS"',
|
|
516
|
+
linux: '"Linux"'
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
const selectedOS = this.weightedRandom(this.osDistribution);
|
|
520
|
+
return platforms[selectedOS] || '"Windows"';
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Generate WebRTC configuration for leak prevention
|
|
525
|
+
*/
|
|
526
|
+
generateWebRTCConfig(config) {
|
|
527
|
+
return {
|
|
528
|
+
publicIP: config.webRTCPublicIP || '192.168.1.' + Math.floor(Math.random() * 255),
|
|
529
|
+
localIPs: config.webRTCLocalIPs || [
|
|
530
|
+
'192.168.1.' + Math.floor(Math.random() * 255),
|
|
531
|
+
'10.0.0.' + Math.floor(Math.random() * 255)
|
|
532
|
+
]
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Advanced Canvas fingerprinting protection with noise injection
|
|
538
|
+
*/
|
|
539
|
+
generateAdvancedCanvasFingerprint() {
|
|
540
|
+
const seed = crypto.randomBytes(16).toString('hex');
|
|
541
|
+
|
|
542
|
+
return {
|
|
543
|
+
seed,
|
|
544
|
+
noisePattern: this.generateCanvasNoise(seed),
|
|
545
|
+
textMetrics: {
|
|
546
|
+
width: this.randomFloat(45, 210, 3),
|
|
547
|
+
height: this.randomFloat(8, 35, 3),
|
|
548
|
+
actualBoundingBoxLeft: this.randomFloat(-2, 5, 3),
|
|
549
|
+
actualBoundingBoxRight: this.randomFloat(50, 200, 3),
|
|
550
|
+
actualBoundingBoxAscent: this.randomFloat(10, 25, 3),
|
|
551
|
+
actualBoundingBoxDescent: this.randomFloat(2, 8, 3)
|
|
552
|
+
},
|
|
553
|
+
imageData: this.generateCanvasImageData(seed)
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Generate consistent canvas noise based on seed
|
|
559
|
+
*/
|
|
560
|
+
generateCanvasNoise(seed) {
|
|
561
|
+
const noise = [];
|
|
562
|
+
let seedNum = parseInt(seed.substring(0, 8), 16);
|
|
563
|
+
|
|
564
|
+
for (let i = 0; i < 100; i++) {
|
|
565
|
+
seedNum = (seedNum * 9301 + 49297) % 233280;
|
|
566
|
+
noise.push((seedNum / 233280) * 2 - 1); // -1 to 1
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
return noise;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
/**
|
|
573
|
+
* Generate canvas image data with controlled randomness
|
|
574
|
+
*/
|
|
575
|
+
generateCanvasImageData(seed) {
|
|
576
|
+
const hash = crypto.createHash('md5').update(seed).digest('hex');
|
|
577
|
+
return {
|
|
578
|
+
checksum: hash.substring(0, 16),
|
|
579
|
+
variance: parseFloat('0.' + hash.substring(16, 24)),
|
|
580
|
+
pixelShift: parseInt(hash.substring(24, 26), 16) % 3
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Enhanced WebGL fingerprinting with realistic spoofing
|
|
586
|
+
*/
|
|
587
|
+
generateAdvancedWebGLFingerprint() {
|
|
588
|
+
const gpuVendors = [
|
|
589
|
+
{ vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA, NVIDIA GeForce GTX 1060 6GB Direct3D11 vs_5_0 ps_5_0, D3D11)' },
|
|
590
|
+
{ vendor: 'Google Inc. (NVIDIA)', renderer: 'ANGLE (NVIDIA, NVIDIA GeForce RTX 3070 Direct3D11 vs_5_0 ps_5_0, D3D11)' },
|
|
591
|
+
{ vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) HD Graphics 630 Direct3D11 vs_5_0 ps_5_0, D3D11)' },
|
|
592
|
+
{ vendor: 'Google Inc. (AMD)', renderer: 'ANGLE (AMD, AMD Radeon RX 580 Series Direct3D11 vs_5_0 ps_5_0, D3D11)' },
|
|
593
|
+
{ vendor: 'Google Inc. (Intel)', renderer: 'ANGLE (Intel, Intel(R) Iris(R) Xe Graphics Direct3D11 vs_5_0 ps_5_0, D3D11)' }
|
|
594
|
+
];
|
|
595
|
+
|
|
596
|
+
const selectedGpu = gpuVendors[Math.floor(Math.random() * gpuVendors.length)];
|
|
597
|
+
|
|
598
|
+
return {
|
|
599
|
+
vendor: selectedGpu.vendor,
|
|
600
|
+
renderer: selectedGpu.renderer,
|
|
601
|
+
version: 'WebGL 1.0 (OpenGL ES 2.0 Chromium)',
|
|
602
|
+
shadingLanguageVersion: 'WebGL GLSL ES 1.0 (OpenGL ES GLSL ES 1.0 Chromium)',
|
|
603
|
+
extensions: this.generateWebGLExtensions(),
|
|
604
|
+
parameters: this.generateWebGLParameters(),
|
|
605
|
+
supportedFormats: this.generateWebGLFormats()
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Generate realistic WebGL extensions list
|
|
611
|
+
*/
|
|
612
|
+
generateWebGLExtensions() {
|
|
613
|
+
const baseExtensions = [
|
|
614
|
+
'ANGLE_instanced_arrays',
|
|
615
|
+
'EXT_blend_minmax',
|
|
616
|
+
'EXT_color_buffer_half_float',
|
|
617
|
+
'EXT_disjoint_timer_query',
|
|
618
|
+
'EXT_float_blend',
|
|
619
|
+
'EXT_frag_depth',
|
|
620
|
+
'EXT_shader_texture_lod',
|
|
621
|
+
'EXT_texture_compression_rgtc',
|
|
622
|
+
'EXT_texture_filter_anisotropic',
|
|
623
|
+
'EXT_sRGB',
|
|
624
|
+
'OES_texture_float',
|
|
625
|
+
'OES_texture_float_linear',
|
|
626
|
+
'OES_texture_half_float',
|
|
627
|
+
'OES_texture_half_float_linear',
|
|
628
|
+
'OES_vertex_array_object',
|
|
629
|
+
'WEBKIT_EXT_texture_filter_anisotropic',
|
|
630
|
+
'WEBKIT_WEBGL_depth_texture'
|
|
631
|
+
];
|
|
632
|
+
|
|
633
|
+
const optionalExtensions = [
|
|
634
|
+
'EXT_color_buffer_float',
|
|
635
|
+
'EXT_texture_compression_bptc',
|
|
636
|
+
'EXT_texture_norm16',
|
|
637
|
+
'OES_draw_buffers_indexed',
|
|
638
|
+
'WEBGL_color_buffer_float',
|
|
639
|
+
'WEBGL_compressed_texture_s3tc',
|
|
640
|
+
'WEBGL_debug_renderer_info',
|
|
641
|
+
'WEBGL_debug_shaders',
|
|
642
|
+
'WEBGL_depth_texture',
|
|
643
|
+
'WEBGL_draw_buffers',
|
|
644
|
+
'WEBGL_lose_context'
|
|
645
|
+
];
|
|
646
|
+
|
|
647
|
+
const extensions = [...baseExtensions];
|
|
648
|
+
|
|
649
|
+
// Randomly include optional extensions (60-90% chance each)
|
|
650
|
+
optionalExtensions.forEach(ext => {
|
|
651
|
+
if (Math.random() < 0.6 + Math.random() * 0.3) {
|
|
652
|
+
extensions.push(ext);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
|
|
656
|
+
return extensions.sort();
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
/**
|
|
660
|
+
* Generate WebGL parameters with realistic values
|
|
661
|
+
*/
|
|
662
|
+
generateWebGLParameters() {
|
|
663
|
+
return {
|
|
664
|
+
MAX_TEXTURE_SIZE: 16384,
|
|
665
|
+
MAX_CUBE_MAP_TEXTURE_SIZE: 16384,
|
|
666
|
+
MAX_RENDERBUFFER_SIZE: 16384,
|
|
667
|
+
MAX_VERTEX_ATTRIBS: 16,
|
|
668
|
+
MAX_VERTEX_UNIFORM_VECTORS: 1024,
|
|
669
|
+
MAX_FRAGMENT_UNIFORM_VECTORS: 1024,
|
|
670
|
+
MAX_VARYING_VECTORS: 30,
|
|
671
|
+
MAX_COMBINED_TEXTURE_IMAGE_UNITS: 32,
|
|
672
|
+
MAX_VERTEX_TEXTURE_IMAGE_UNITS: 16,
|
|
673
|
+
MAX_TEXTURE_IMAGE_UNITS: 16,
|
|
674
|
+
MAX_VIEWPORT_DIMS: [16384, 16384],
|
|
675
|
+
ALIASED_LINE_WIDTH_RANGE: [1, 1],
|
|
676
|
+
ALIASED_POINT_SIZE_RANGE: [1, 1024]
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Generate WebGL supported formats
|
|
682
|
+
*/
|
|
683
|
+
generateWebGLFormats() {
|
|
684
|
+
return {
|
|
685
|
+
textureFormats: ['RGB', 'RGBA', 'LUMINANCE', 'LUMINANCE_ALPHA', 'ALPHA'],
|
|
686
|
+
compressedFormats: ['COMPRESSED_RGB_S3TC_DXT1_EXT', 'COMPRESSED_RGBA_S3TC_DXT5_EXT'],
|
|
687
|
+
depthFormats: ['DEPTH_COMPONENT16', 'DEPTH_STENCIL'],
|
|
688
|
+
pixelTypes: ['UNSIGNED_BYTE', 'UNSIGNED_SHORT_4_4_4_4', 'UNSIGNED_SHORT_5_5_5_1', 'UNSIGNED_SHORT_5_6_5']
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Advanced audio context spoofing
|
|
694
|
+
*/
|
|
695
|
+
generateAudioContextFingerprint() {
|
|
696
|
+
return {
|
|
697
|
+
sampleRate: 44100 + Math.floor(Math.random() * 2000), // Slight variation
|
|
698
|
+
baseLatency: this.randomFloat(0.005, 0.02, 6),
|
|
699
|
+
outputLatency: this.randomFloat(0.01, 0.05, 6),
|
|
700
|
+
maxChannelCount: 2 + Math.floor(Math.random() * 6), // 2-8 channels
|
|
701
|
+
numberOfInputs: Math.floor(Math.random() * 2) + 1,
|
|
702
|
+
numberOfOutputs: Math.floor(Math.random() * 2) + 1,
|
|
703
|
+
channelCount: 2,
|
|
704
|
+
channelCountMode: 'max',
|
|
705
|
+
channelInterpretation: 'speakers'
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/**
|
|
710
|
+
* Enhanced media devices spoofing
|
|
711
|
+
*/
|
|
712
|
+
generateMediaDevicesFingerprint() {
|
|
713
|
+
const videoDevices = [
|
|
714
|
+
{ deviceId: crypto.randomUUID(), kind: 'videoinput', label: 'HD Pro Webcam C920 (046d:082d)', groupId: crypto.randomUUID() },
|
|
715
|
+
{ deviceId: crypto.randomUUID(), kind: 'videoinput', label: 'FaceTime HD Camera', groupId: crypto.randomUUID() },
|
|
716
|
+
{ deviceId: crypto.randomUUID(), kind: 'videoinput', label: 'Integrated Camera', groupId: crypto.randomUUID() }
|
|
717
|
+
];
|
|
718
|
+
|
|
719
|
+
const audioDevices = [
|
|
720
|
+
{ deviceId: crypto.randomUUID(), kind: 'audioinput', label: 'Default - Internal Microphone', groupId: crypto.randomUUID() },
|
|
721
|
+
{ deviceId: crypto.randomUUID(), kind: 'audiooutput', label: 'Default - Internal Speakers', groupId: crypto.randomUUID() },
|
|
722
|
+
{ deviceId: crypto.randomUUID(), kind: 'audioinput', label: 'Communications - Internal Microphone', groupId: crypto.randomUUID() }
|
|
723
|
+
];
|
|
724
|
+
|
|
725
|
+
// Randomly select devices
|
|
726
|
+
const selectedDevices = [];
|
|
727
|
+
if (Math.random() < 0.8) selectedDevices.push(videoDevices[Math.floor(Math.random() * videoDevices.length)]);
|
|
728
|
+
if (Math.random() < 0.9) selectedDevices.push(...audioDevices.slice(0, Math.floor(Math.random() * audioDevices.length) + 1));
|
|
729
|
+
|
|
730
|
+
return selectedDevices;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Generate realistic hardware fingerprint
|
|
735
|
+
*/
|
|
736
|
+
generateHardwareFingerprint() {
|
|
737
|
+
const processors = [
|
|
738
|
+
{ cores: 4, threads: 8, name: 'Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz' },
|
|
739
|
+
{ cores: 6, threads: 12, name: 'Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz' },
|
|
740
|
+
{ cores: 8, threads: 16, name: 'Intel(R) Core(TM) i7-10700K CPU @ 3.80GHz' },
|
|
741
|
+
{ cores: 4, threads: 4, name: 'Intel(R) Core(TM) i5-7400 CPU @ 3.00GHz' },
|
|
742
|
+
{ cores: 6, threads: 6, name: 'AMD Ryzen 5 3600 6-Core Processor' },
|
|
743
|
+
{ cores: 8, threads: 16, name: 'AMD Ryzen 7 3700X 8-Core Processor' }
|
|
744
|
+
];
|
|
745
|
+
|
|
746
|
+
const selectedProcessor = processors[Math.floor(Math.random() * processors.length)];
|
|
747
|
+
|
|
748
|
+
return {
|
|
749
|
+
hardwareConcurrency: selectedProcessor.threads,
|
|
750
|
+
processor: selectedProcessor.name,
|
|
751
|
+
architecture: Math.random() < 0.9 ? 'x86_64' : 'arm64',
|
|
752
|
+
memory: Math.floor(Math.random() * 24) + 8, // 8-32 GB
|
|
753
|
+
deviceMemory: Math.pow(2, Math.floor(Math.random() * 3) + 3), // 8, 16, or 32 GB
|
|
754
|
+
platform: this.selectRealisticPlatform()
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/**
|
|
759
|
+
* Select realistic platform based on distribution
|
|
760
|
+
*/
|
|
761
|
+
selectRealisticPlatform() {
|
|
762
|
+
const platforms = {
|
|
763
|
+
'Win32': 0.75,
|
|
764
|
+
'MacIntel': 0.15,
|
|
765
|
+
'Linux x86_64': 0.08,
|
|
766
|
+
'Linux armv7l': 0.02
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
return this.weightedRandom(platforms);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Generate advanced font list with realistic variation
|
|
774
|
+
*/
|
|
775
|
+
generateAdvancedFontList() {
|
|
776
|
+
const baseFonts = [
|
|
777
|
+
'Arial', 'Helvetica', 'Times New Roman', 'Courier New', 'Verdana',
|
|
778
|
+
'Georgia', 'Palatino', 'Garamond', 'Bookman', 'Tahoma', 'Geneva'
|
|
779
|
+
];
|
|
780
|
+
|
|
781
|
+
const systemFonts = {
|
|
782
|
+
windows: ['Segoe UI', 'Calibri', 'Consolas', 'Cambria', 'Candara'],
|
|
783
|
+
macos: ['SF Pro Display', 'Helvetica Neue', 'Menlo', 'Avenir', 'Optima'],
|
|
784
|
+
linux: ['Ubuntu', 'DejaVu Sans', 'Liberation Sans', 'Noto Sans', 'Source Sans Pro']
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
const additionalFonts = [
|
|
788
|
+
'Comic Sans MS', 'Trebuchet MS', 'Arial Black', 'Impact',
|
|
789
|
+
'Lucida Sans Unicode', 'Franklin Gothic Medium', 'Arial Narrow'
|
|
790
|
+
];
|
|
791
|
+
|
|
792
|
+
// Start with base fonts
|
|
793
|
+
const fonts = [...baseFonts];
|
|
794
|
+
|
|
795
|
+
// Add system-specific fonts based on platform
|
|
796
|
+
const platform = this.selectRealisticPlatform();
|
|
797
|
+
let osKey = 'windows';
|
|
798
|
+
if (platform.includes('Mac')) osKey = 'macos';
|
|
799
|
+
else if (platform.includes('Linux')) osKey = 'linux';
|
|
800
|
+
|
|
801
|
+
systemFonts[osKey].forEach(font => {
|
|
802
|
+
if (Math.random() < 0.8) { // 80% chance to include
|
|
803
|
+
fonts.push(font);
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
|
|
807
|
+
// Randomly include additional fonts
|
|
808
|
+
additionalFonts.forEach(font => {
|
|
809
|
+
if (Math.random() < 0.6) {
|
|
810
|
+
fonts.push(font);
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
|
|
814
|
+
return fonts.sort();
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Generate advanced plugin list
|
|
819
|
+
*/
|
|
820
|
+
generateAdvancedPluginList() {
|
|
821
|
+
const plugins = [];
|
|
822
|
+
|
|
823
|
+
// Chrome PDF Plugin (almost always present)
|
|
824
|
+
if (Math.random() < 0.95) {
|
|
825
|
+
plugins.push({
|
|
826
|
+
name: 'Chrome PDF Plugin',
|
|
827
|
+
filename: 'internal-pdf-viewer',
|
|
828
|
+
description: 'Portable Document Format',
|
|
829
|
+
version: '1'
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Chrome PDF Viewer
|
|
834
|
+
if (Math.random() < 0.8) {
|
|
835
|
+
plugins.push({
|
|
836
|
+
name: 'Chrome PDF Viewer',
|
|
837
|
+
filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
|
|
838
|
+
description: 'Portable Document Format',
|
|
839
|
+
version: '1'
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// Native Client
|
|
844
|
+
if (Math.random() < 0.3) {
|
|
845
|
+
plugins.push({
|
|
846
|
+
name: 'Native Client',
|
|
847
|
+
filename: 'internal-nacl-plugin',
|
|
848
|
+
description: 'Native Client Executable',
|
|
849
|
+
version: '1'
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
return plugins;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
/**
|
|
857
|
+
* Generate realistic geolocation data
|
|
858
|
+
*/
|
|
859
|
+
generateRealisticGeolocation() {
|
|
860
|
+
// Random coordinates in major cities with realistic distribution
|
|
861
|
+
const cities = [
|
|
862
|
+
{ latitude: 40.7128, longitude: -74.0060, weight: 0.15 }, // New York
|
|
863
|
+
{ latitude: 34.0522, longitude: -118.2437, weight: 0.12 }, // Los Angeles
|
|
864
|
+
{ latitude: 51.5074, longitude: -0.1278, weight: 0.10 }, // London
|
|
865
|
+
{ latitude: 48.8566, longitude: 2.3522, weight: 0.08 }, // Paris
|
|
866
|
+
{ latitude: 35.6762, longitude: 139.6503, weight: 0.07 }, // Tokyo
|
|
867
|
+
{ latitude: -33.8688, longitude: 151.2093, weight: 0.05 }, // Sydney
|
|
868
|
+
{ latitude: 52.5200, longitude: 13.4050, weight: 0.05 }, // Berlin
|
|
869
|
+
{ latitude: 37.7749, longitude: -122.4194, weight: 0.08 }, // San Francisco
|
|
870
|
+
{ latitude: 41.8781, longitude: -87.6298, weight: 0.06 }, // Chicago
|
|
871
|
+
{ latitude: 55.7558, longitude: 37.6176, weight: 0.04 }, // Moscow
|
|
872
|
+
{ latitude: 39.9042, longitude: 116.4074, weight: 0.06 }, // Beijing
|
|
873
|
+
{ latitude: 28.6139, longitude: 77.2090, weight: 0.05 }, // Delhi
|
|
874
|
+
{ latitude: -23.5505, longitude: -46.6333, weight: 0.04 }, // São Paulo
|
|
875
|
+
{ latitude: 19.4326, longitude: -99.1332, weight: 0.05 } // Mexico City
|
|
876
|
+
];
|
|
877
|
+
|
|
878
|
+
const city = this.weightedRandomFromArray(cities);
|
|
879
|
+
|
|
880
|
+
return {
|
|
881
|
+
latitude: city.latitude + (Math.random() - 0.5) * 0.05, // ±0.025 degrees (~2.8km)
|
|
882
|
+
longitude: city.longitude + (Math.random() - 0.5) * 0.05,
|
|
883
|
+
accuracy: Math.floor(Math.random() * 50) + 20 // 20-70m accuracy
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
/**
|
|
888
|
+
* Generate advanced screen properties
|
|
889
|
+
*/
|
|
890
|
+
generateAdvancedScreenProperties() {
|
|
891
|
+
const viewport = this.selectWeightedViewport();
|
|
892
|
+
|
|
893
|
+
return {
|
|
894
|
+
width: viewport.width,
|
|
895
|
+
height: viewport.height,
|
|
896
|
+
availWidth: viewport.width,
|
|
897
|
+
availHeight: viewport.height - (30 + Math.floor(Math.random() * 20)), // Account for taskbar
|
|
898
|
+
colorDepth: Math.random() < 0.95 ? 24 : 32,
|
|
899
|
+
pixelDepth: 24,
|
|
900
|
+
orientation: {
|
|
901
|
+
angle: 0,
|
|
902
|
+
type: 'landscape-primary'
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* Generate battery API fingerprint
|
|
909
|
+
*/
|
|
910
|
+
generateBatteryFingerprint() {
|
|
911
|
+
return {
|
|
912
|
+
charging: Math.random() < 0.7, // 70% chance charging
|
|
913
|
+
chargingTime: Math.random() < 0.3 ? Math.floor(Math.random() * 7200) : Infinity,
|
|
914
|
+
dischargingTime: Math.random() < 0.7 ? Math.floor(Math.random() * 28800) + 3600 : Infinity, // 1-9 hours
|
|
915
|
+
level: Math.random() * 0.7 + 0.2 // 20-90%
|
|
916
|
+
};
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
/**
|
|
920
|
+
* Apply advanced stealth configurations to browser context
|
|
921
|
+
*/
|
|
922
|
+
async applyAdvancedStealthConfigurations(context, config, fingerprint) {
|
|
923
|
+
// Enhanced initialization script with comprehensive stealth measures
|
|
924
|
+
await context.addInitScript(() => {
|
|
925
|
+
// Remove webdriver property completely
|
|
926
|
+
Object.defineProperty(navigator, 'webdriver', {
|
|
927
|
+
get: () => undefined,
|
|
928
|
+
configurable: true
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
// Hide automation indicators
|
|
932
|
+
delete window.navigator.__proto__.webdriver;
|
|
933
|
+
delete window.navigator.webdriver;
|
|
934
|
+
delete window.webdriver;
|
|
935
|
+
delete window._phantom;
|
|
936
|
+
delete window.__nightmare;
|
|
937
|
+
delete window._selenium;
|
|
938
|
+
|
|
939
|
+
// Override chrome runtime
|
|
940
|
+
if (!window.chrome) {
|
|
941
|
+
window.chrome = {};
|
|
942
|
+
}
|
|
943
|
+
window.chrome.runtime = {
|
|
944
|
+
onConnect: undefined,
|
|
945
|
+
onMessage: undefined,
|
|
946
|
+
connect: undefined,
|
|
947
|
+
sendMessage: undefined
|
|
948
|
+
};
|
|
949
|
+
|
|
950
|
+
// Override permissions API
|
|
951
|
+
const originalQuery = window.navigator.permissions.query;
|
|
952
|
+
window.navigator.permissions.query = (parameters) => (
|
|
953
|
+
parameters.name === 'notifications' ?
|
|
954
|
+
Promise.resolve({ state: Notification.permission }) :
|
|
955
|
+
originalQuery(parameters)
|
|
956
|
+
);
|
|
957
|
+
|
|
958
|
+
// Hide headless indicators
|
|
959
|
+
Object.defineProperty(navigator, 'hardwareConcurrency', {
|
|
960
|
+
get: () => 4
|
|
961
|
+
});
|
|
962
|
+
|
|
963
|
+
// Spoof connection
|
|
964
|
+
Object.defineProperty(navigator, 'connection', {
|
|
965
|
+
get: () => ({
|
|
966
|
+
effectiveType: '4g',
|
|
967
|
+
rtt: 50 + Math.random() * 50,
|
|
968
|
+
downlink: 10,
|
|
969
|
+
saveData: false
|
|
970
|
+
})
|
|
971
|
+
});
|
|
972
|
+
|
|
973
|
+
// Override plugin array
|
|
974
|
+
Object.defineProperty(navigator, 'plugins', {
|
|
975
|
+
get: function() {
|
|
976
|
+
const plugins = [
|
|
977
|
+
{
|
|
978
|
+
0: {
|
|
979
|
+
type: "application/x-google-chrome-pdf",
|
|
980
|
+
suffixes: "pdf",
|
|
981
|
+
description: "Portable Document Format"
|
|
982
|
+
},
|
|
983
|
+
description: "Portable Document Format",
|
|
984
|
+
filename: "internal-pdf-viewer",
|
|
985
|
+
length: 1,
|
|
986
|
+
name: "Chrome PDF Plugin"
|
|
987
|
+
}
|
|
988
|
+
];
|
|
989
|
+
plugins.item = function(index) { return this[index] || null; };
|
|
990
|
+
plugins.namedItem = function(name) {
|
|
991
|
+
return this.find(plugin => plugin.name === name) || null;
|
|
992
|
+
};
|
|
993
|
+
return plugins;
|
|
994
|
+
}
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
// Override languages with realistic patterns
|
|
998
|
+
Object.defineProperty(navigator, 'languages', {
|
|
999
|
+
get: function() {
|
|
1000
|
+
return ['en-US', 'en'];
|
|
1001
|
+
}
|
|
1002
|
+
});
|
|
1003
|
+
|
|
1004
|
+
// Mock battery API with realistic values
|
|
1005
|
+
Object.defineProperty(navigator, 'getBattery', {
|
|
1006
|
+
get: function() {
|
|
1007
|
+
return function() {
|
|
1008
|
+
return Promise.resolve({
|
|
1009
|
+
charging: true,
|
|
1010
|
+
chargingTime: 0,
|
|
1011
|
+
dischargingTime: Infinity,
|
|
1012
|
+
level: 0.8 + Math.random() * 0.19 // 80-99%
|
|
1013
|
+
});
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
// Override Date.prototype.getTimezoneOffset if timezone spoofing is enabled
|
|
1019
|
+
if (window.stealthTimezone) {
|
|
1020
|
+
const originalGetTimezoneOffset = Date.prototype.getTimezoneOffset;
|
|
1021
|
+
Date.prototype.getTimezoneOffset = function() {
|
|
1022
|
+
// Return offset for spoofed timezone
|
|
1023
|
+
const timezoneOffsets = {
|
|
1024
|
+
'America/New_York': 300,
|
|
1025
|
+
'America/Los_Angeles': 480,
|
|
1026
|
+
'Europe/London': 0,
|
|
1027
|
+
'Asia/Tokyo': -540
|
|
1028
|
+
};
|
|
1029
|
+
return timezoneOffsets[window.stealthTimezone] || originalGetTimezoneOffset.call(this);
|
|
1030
|
+
};
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// Modify Error.prepareStackTrace to hide automation
|
|
1034
|
+
if (Error.prepareStackTrace) {
|
|
1035
|
+
const originalPrepareStackTrace = Error.prepareStackTrace;
|
|
1036
|
+
Error.prepareStackTrace = function(error, stack) {
|
|
1037
|
+
const filteredStack = stack.filter(frame => {
|
|
1038
|
+
const frameString = frame.toString();
|
|
1039
|
+
return !frameString.includes('puppeteer') &&
|
|
1040
|
+
!frameString.includes('playwright') &&
|
|
1041
|
+
!frameString.includes('selenium');
|
|
1042
|
+
});
|
|
1043
|
+
return originalPrepareStackTrace.call(this, error, filteredStack);
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
// WebRTC leak prevention with advanced spoofing
|
|
1049
|
+
if (config.blockWebRTC) {
|
|
1050
|
+
await context.addInitScript((webrtcConfig) => {
|
|
1051
|
+
// Override RTCPeerConnection
|
|
1052
|
+
const originalRTCPeerConnection = window.RTCPeerConnection ||
|
|
1053
|
+
window.webkitRTCPeerConnection ||
|
|
1054
|
+
window.mozRTCPeerConnection;
|
|
1055
|
+
|
|
1056
|
+
if (originalRTCPeerConnection) {
|
|
1057
|
+
const StealthRTCPeerConnection = function(...args) {
|
|
1058
|
+
const pc = new originalRTCPeerConnection(...args);
|
|
1059
|
+
|
|
1060
|
+
const originalCreateOffer = pc.createOffer;
|
|
1061
|
+
pc.createOffer = function(...offerArgs) {
|
|
1062
|
+
return originalCreateOffer.apply(this, offerArgs).then(offer => {
|
|
1063
|
+
// Modify SDP to use fake IP
|
|
1064
|
+
offer.sdp = offer.sdp.replace(
|
|
1065
|
+
/c=IN IP4 .*\r\n/g,
|
|
1066
|
+
'c=IN IP4 ' + webrtcConfig.publicIP + '\r\n'
|
|
1067
|
+
);
|
|
1068
|
+
return offer;
|
|
1069
|
+
});
|
|
1070
|
+
};
|
|
1071
|
+
|
|
1072
|
+
return pc;
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
StealthRTCPeerConnection.prototype = originalRTCPeerConnection.prototype;
|
|
1076
|
+
window.RTCPeerConnection = StealthRTCPeerConnection;
|
|
1077
|
+
window.webkitRTCPeerConnection = StealthRTCPeerConnection;
|
|
1078
|
+
}
|
|
1079
|
+
}, fingerprint.webRTC);
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
// Advanced canvas fingerprinting protection
|
|
1083
|
+
if (config.fingerprinting?.canvasNoise) {
|
|
1084
|
+
await context.addInitScript((canvasConfig) => {
|
|
1085
|
+
const getContext = HTMLCanvasElement.prototype.getContext;
|
|
1086
|
+
HTMLCanvasElement.prototype.getContext = function(contextType, contextAttributes) {
|
|
1087
|
+
const ctx = getContext.call(this, contextType, contextAttributes);
|
|
1088
|
+
|
|
1089
|
+
if (contextType === '2d') {
|
|
1090
|
+
const originalToDataURL = this.toDataURL;
|
|
1091
|
+
this.toDataURL = function(...args) {
|
|
1092
|
+
// Add controlled noise based on seed
|
|
1093
|
+
const imageData = ctx.getImageData(0, 0, this.width, this.height);
|
|
1094
|
+
const noise = canvasConfig.noisePattern;
|
|
1095
|
+
|
|
1096
|
+
for (let i = 0; i < imageData.data.length; i += 4) {
|
|
1097
|
+
const noiseIndex = i % noise.length;
|
|
1098
|
+
const noiseValue = noise[noiseIndex] * canvasConfig.imageData.pixelShift;
|
|
1099
|
+
|
|
1100
|
+
imageData.data[i] = Math.min(255, Math.max(0, imageData.data[i] + noiseValue));
|
|
1101
|
+
imageData.data[i + 1] = Math.min(255, Math.max(0, imageData.data[i + 1] + noiseValue));
|
|
1102
|
+
imageData.data[i + 2] = Math.min(255, Math.max(0, imageData.data[i + 2] + noiseValue));
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
ctx.putImageData(imageData, 0, 0);
|
|
1106
|
+
return originalToDataURL.apply(this, args);
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
return ctx;
|
|
1111
|
+
};
|
|
1112
|
+
}, fingerprint.canvas);
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// WebGL spoofing
|
|
1116
|
+
if (config.fingerprinting?.webglSpoofing) {
|
|
1117
|
+
await context.addInitScript((webglConfig) => {
|
|
1118
|
+
const getContext = HTMLCanvasElement.prototype.getContext;
|
|
1119
|
+
HTMLCanvasElement.prototype.getContext = function(contextType, contextAttributes) {
|
|
1120
|
+
const ctx = getContext.call(this, contextType, contextAttributes);
|
|
1121
|
+
|
|
1122
|
+
if (contextType === 'webgl' || contextType === 'experimental-webgl') {
|
|
1123
|
+
const originalGetParameter = ctx.getParameter;
|
|
1124
|
+
ctx.getParameter = function(parameter) {
|
|
1125
|
+
// Spoof specific WebGL parameters
|
|
1126
|
+
if (parameter === ctx.RENDERER) {
|
|
1127
|
+
return webglConfig.renderer;
|
|
1128
|
+
}
|
|
1129
|
+
if (parameter === ctx.VENDOR) {
|
|
1130
|
+
return webglConfig.vendor;
|
|
1131
|
+
}
|
|
1132
|
+
if (parameter === ctx.VERSION) {
|
|
1133
|
+
return webglConfig.version;
|
|
1134
|
+
}
|
|
1135
|
+
if (parameter === ctx.SHADING_LANGUAGE_VERSION) {
|
|
1136
|
+
return webglConfig.shadingLanguageVersion;
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
return originalGetParameter.call(this, parameter);
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
const originalGetExtension = ctx.getExtension;
|
|
1143
|
+
ctx.getExtension = function(name) {
|
|
1144
|
+
if (webglConfig.extensions.includes(name)) {
|
|
1145
|
+
return originalGetExtension.call(this, name) || {};
|
|
1146
|
+
}
|
|
1147
|
+
return null;
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
return ctx;
|
|
1152
|
+
};
|
|
1153
|
+
}, fingerprint.webGL);
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// Audio context spoofing
|
|
1157
|
+
if (config.fingerprinting?.audioContextSpoofing) {
|
|
1158
|
+
await context.addInitScript((audioConfig) => {
|
|
1159
|
+
const OriginalAudioContext = window.AudioContext || window.webkitAudioContext;
|
|
1160
|
+
|
|
1161
|
+
if (OriginalAudioContext) {
|
|
1162
|
+
window.AudioContext = function(...args) {
|
|
1163
|
+
const ctx = new OriginalAudioContext(...args);
|
|
1164
|
+
|
|
1165
|
+
Object.defineProperty(ctx, 'sampleRate', {
|
|
1166
|
+
get: () => audioConfig.sampleRate
|
|
1167
|
+
});
|
|
1168
|
+
|
|
1169
|
+
Object.defineProperty(ctx, 'baseLatency', {
|
|
1170
|
+
get: () => audioConfig.baseLatency
|
|
1171
|
+
});
|
|
1172
|
+
|
|
1173
|
+
Object.defineProperty(ctx, 'outputLatency', {
|
|
1174
|
+
get: () => audioConfig.outputLatency
|
|
1175
|
+
});
|
|
1176
|
+
|
|
1177
|
+
return ctx;
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
if (window.webkitAudioContext) {
|
|
1181
|
+
window.webkitAudioContext = window.AudioContext;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}, fingerprint.audioContext);
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// Media devices spoofing
|
|
1188
|
+
if (config.antiDetection?.spoofMediaDevices) {
|
|
1189
|
+
await context.addInitScript((mediaDevices) => {
|
|
1190
|
+
if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
|
|
1191
|
+
const originalEnumerateDevices = navigator.mediaDevices.enumerateDevices;
|
|
1192
|
+
navigator.mediaDevices.enumerateDevices = function() {
|
|
1193
|
+
return Promise.resolve(mediaDevices);
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1196
|
+
}, fingerprint.mediaDevices);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
// Hardware spoofing
|
|
1200
|
+
if (config.fingerprinting?.hardwareSpoofing) {
|
|
1201
|
+
await context.addInitScript((hardware) => {
|
|
1202
|
+
Object.defineProperty(navigator, 'hardwareConcurrency', {
|
|
1203
|
+
get: () => hardware.hardwareConcurrency
|
|
1204
|
+
});
|
|
1205
|
+
|
|
1206
|
+
Object.defineProperty(navigator, 'platform', {
|
|
1207
|
+
get: () => hardware.platform
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
if (navigator.deviceMemory !== undefined) {
|
|
1211
|
+
Object.defineProperty(navigator, 'deviceMemory', {
|
|
1212
|
+
get: () => hardware.deviceMemory
|
|
1213
|
+
});
|
|
1214
|
+
}
|
|
1215
|
+
}, fingerprint.hardware);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// Font spoofing
|
|
1219
|
+
if (config.fingerprinting?.fontSpoofing) {
|
|
1220
|
+
await context.addInitScript((fonts) => {
|
|
1221
|
+
// Override font detection methods
|
|
1222
|
+
const originalMeasureText = CanvasRenderingContext2D.prototype.measureText;
|
|
1223
|
+
CanvasRenderingContext2D.prototype.measureText = function(text) {
|
|
1224
|
+
const result = originalMeasureText.call(this, text);
|
|
1225
|
+
|
|
1226
|
+
// Add slight variations to font measurements
|
|
1227
|
+
const variance = 0.1 + Math.random() * 0.1;
|
|
1228
|
+
return {
|
|
1229
|
+
width: result.width * variance,
|
|
1230
|
+
actualBoundingBoxLeft: result.actualBoundingBoxLeft || 0,
|
|
1231
|
+
actualBoundingBoxRight: result.actualBoundingBoxRight || result.width,
|
|
1232
|
+
fontBoundingBoxAscent: result.fontBoundingBoxAscent || 10,
|
|
1233
|
+
fontBoundingBoxDescent: result.fontBoundingBoxDescent || 2,
|
|
1234
|
+
actualBoundingBoxAscent: result.actualBoundingBoxAscent || 8,
|
|
1235
|
+
actualBoundingBoxDescent: result.actualBoundingBoxDescent || 2,
|
|
1236
|
+
emHeightAscent: result.emHeightAscent || 8,
|
|
1237
|
+
emHeightDescent: result.emHeightDescent || 2,
|
|
1238
|
+
hangingBaseline: result.hangingBaseline || 6,
|
|
1239
|
+
alphabeticBaseline: result.alphabeticBaseline || 0,
|
|
1240
|
+
ideographicBaseline: result.ideographicBaseline || -2
|
|
1241
|
+
};
|
|
1242
|
+
};
|
|
1243
|
+
}, fingerprint.fonts);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// Screen resolution spoofing
|
|
1247
|
+
await context.addInitScript((screenConfig) => {
|
|
1248
|
+
Object.defineProperties(screen, {
|
|
1249
|
+
width: { value: screenConfig.width, configurable: true },
|
|
1250
|
+
height: { value: screenConfig.height, configurable: true },
|
|
1251
|
+
availWidth: { value: screenConfig.availWidth, configurable: true },
|
|
1252
|
+
availHeight: { value: screenConfig.availHeight, configurable: true },
|
|
1253
|
+
colorDepth: { value: screenConfig.colorDepth, configurable: true },
|
|
1254
|
+
pixelDepth: { value: screenConfig.pixelDepth, configurable: true }
|
|
1255
|
+
});
|
|
1256
|
+
}, fingerprint.screen);
|
|
1257
|
+
|
|
1258
|
+
// Timezone spoofing
|
|
1259
|
+
if (config.spoofTimezone) {
|
|
1260
|
+
await context.addInitScript((timezone) => {
|
|
1261
|
+
window.stealthTimezone = timezone;
|
|
1262
|
+
|
|
1263
|
+
// Override Intl.DateTimeFormat
|
|
1264
|
+
const originalDateTimeFormat = Intl.DateTimeFormat;
|
|
1265
|
+
Intl.DateTimeFormat = function(locales, options = {}) {
|
|
1266
|
+
if (!options.timeZone) {
|
|
1267
|
+
options.timeZone = timezone;
|
|
1268
|
+
}
|
|
1269
|
+
return new originalDateTimeFormat(locales, options);
|
|
1270
|
+
};
|
|
1271
|
+
|
|
1272
|
+
// Override Date methods
|
|
1273
|
+
const originalToLocaleDateString = Date.prototype.toLocaleDateString;
|
|
1274
|
+
Date.prototype.toLocaleDateString = function(locales, options = {}) {
|
|
1275
|
+
if (!options.timeZone) {
|
|
1276
|
+
options.timeZone = timezone;
|
|
1277
|
+
}
|
|
1278
|
+
return originalToLocaleDateString.call(this, locales, options);
|
|
1279
|
+
};
|
|
1280
|
+
}, fingerprint.timezone);
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
// Battery API spoofing
|
|
1284
|
+
if (config.antiDetection?.spoofBatteryAPI) {
|
|
1285
|
+
await context.addInitScript((battery) => {
|
|
1286
|
+
if (navigator.getBattery) {
|
|
1287
|
+
navigator.getBattery = function() {
|
|
1288
|
+
return Promise.resolve(battery);
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
}, fingerprint.battery);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
/**
|
|
1296
|
+
* Enhanced human behavior simulation using dedicated simulator
|
|
1297
|
+
*/
|
|
1298
|
+
async initializeHumanBehaviorSimulator(config = {}) {
|
|
1299
|
+
if (!this.humanBehaviorSimulator) {
|
|
1300
|
+
this.humanBehaviorSimulator = new HumanBehaviorSimulator({
|
|
1301
|
+
mouseMovements: {
|
|
1302
|
+
enabled: true,
|
|
1303
|
+
speed: 'normal',
|
|
1304
|
+
accuracy: 0.85,
|
|
1305
|
+
naturalCurves: true,
|
|
1306
|
+
randomMicroMovements: true
|
|
1307
|
+
},
|
|
1308
|
+
typing: {
|
|
1309
|
+
enabled: true,
|
|
1310
|
+
speed: 'normal',
|
|
1311
|
+
variability: 0.3,
|
|
1312
|
+
mistakes: {
|
|
1313
|
+
enabled: true,
|
|
1314
|
+
frequency: 0.015, // 1.5% mistake rate
|
|
1315
|
+
correctionDelay: 600
|
|
1316
|
+
}
|
|
1317
|
+
},
|
|
1318
|
+
scrolling: {
|
|
1319
|
+
enabled: true,
|
|
1320
|
+
naturalAcceleration: true,
|
|
1321
|
+
randomPauses: true,
|
|
1322
|
+
scrollBackProbability: 0.12
|
|
1323
|
+
},
|
|
1324
|
+
interactions: {
|
|
1325
|
+
hoverBeforeClick: true,
|
|
1326
|
+
clickDelay: { min: 120, max: 350 },
|
|
1327
|
+
focusBlurSimulation: true,
|
|
1328
|
+
idlePeriods: {
|
|
1329
|
+
enabled: true,
|
|
1330
|
+
frequency: 0.08,
|
|
1331
|
+
minDuration: 800,
|
|
1332
|
+
maxDuration: 3500
|
|
1333
|
+
}
|
|
1334
|
+
},
|
|
1335
|
+
...config
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
return this.humanBehaviorSimulator;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
/**
|
|
1342
|
+
* Advanced CloudFlare detection and bypass
|
|
1343
|
+
*/
|
|
1344
|
+
async bypassCloudflareChallenge(page) {
|
|
1345
|
+
try {
|
|
1346
|
+
this.performanceMetrics.detectionAttempts++;
|
|
1347
|
+
|
|
1348
|
+
// Wait for potential challenge page
|
|
1349
|
+
await page.waitForTimeout(2000);
|
|
1350
|
+
|
|
1351
|
+
// Check for CloudFlare challenge indicators
|
|
1352
|
+
const challengeDetected = await page.evaluate(() => {
|
|
1353
|
+
const indicators = [
|
|
1354
|
+
'cf-browser-verification',
|
|
1355
|
+
'cf-challenge-running',
|
|
1356
|
+
'Checking your browser',
|
|
1357
|
+
'DDoS protection by Cloudflare',
|
|
1358
|
+
'Ray ID'
|
|
1359
|
+
];
|
|
1360
|
+
|
|
1361
|
+
const pageText = document.body.innerText;
|
|
1362
|
+
return indicators.some(indicator => pageText.includes(indicator));
|
|
1363
|
+
});
|
|
1364
|
+
|
|
1365
|
+
if (challengeDetected) {
|
|
1366
|
+
console.log('CloudFlare challenge detected, attempting bypass...');
|
|
1367
|
+
|
|
1368
|
+
// Simulate human behavior during challenge
|
|
1369
|
+
if (this.humanBehaviorSimulator) {
|
|
1370
|
+
await this.humanBehaviorSimulator.simulateIdlePeriod();
|
|
1371
|
+
|
|
1372
|
+
// Random mouse movements during challenge
|
|
1373
|
+
const viewport = await page.viewportSize();
|
|
1374
|
+
for (let i = 0; i < 3; i++) {
|
|
1375
|
+
const x = Math.random() * viewport.width;
|
|
1376
|
+
const y = Math.random() * viewport.height;
|
|
1377
|
+
await this.humanBehaviorSimulator.simulateMouseMovement(
|
|
1378
|
+
page, x - 50, y - 50, x, y
|
|
1379
|
+
);
|
|
1380
|
+
await this.humanBehaviorSimulator.delay(1000, 0.3);
|
|
1381
|
+
}
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// Wait for challenge to complete (up to 30 seconds)
|
|
1385
|
+
await page.waitForFunction(() => {
|
|
1386
|
+
const indicators = [
|
|
1387
|
+
'cf-browser-verification',
|
|
1388
|
+
'cf-challenge-running',
|
|
1389
|
+
'Checking your browser'
|
|
1390
|
+
];
|
|
1391
|
+
const pageText = document.body.innerText;
|
|
1392
|
+
return !indicators.some(indicator => pageText.includes(indicator));
|
|
1393
|
+
}, { timeout: 30000 }).catch(() => {});
|
|
1394
|
+
|
|
1395
|
+
this.performanceMetrics.successfulBypasses++;
|
|
1396
|
+
return true;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
return false;
|
|
1400
|
+
} catch (error) {
|
|
1401
|
+
this.performanceMetrics.failedBypasses++;
|
|
1402
|
+
console.warn('CloudFlare bypass failed:', error.message);
|
|
1403
|
+
return false;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* Enhanced reCAPTCHA detection and handling
|
|
1409
|
+
*/
|
|
1410
|
+
async handleRecaptcha(page) {
|
|
1411
|
+
try {
|
|
1412
|
+
// Check for reCAPTCHA elements
|
|
1413
|
+
const recaptchaDetected = await page.evaluate(() => {
|
|
1414
|
+
const recaptchaElements = [
|
|
1415
|
+
'.g-recaptcha',
|
|
1416
|
+
'#recaptcha',
|
|
1417
|
+
'[data-sitekey]',
|
|
1418
|
+
'iframe[src*="recaptcha"]'
|
|
1419
|
+
];
|
|
1420
|
+
|
|
1421
|
+
return recaptchaElements.some(selector =>
|
|
1422
|
+
document.querySelector(selector) !== null
|
|
1423
|
+
);
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
if (recaptchaDetected) {
|
|
1427
|
+
console.log('reCAPTCHA detected, implementing human behavior...');
|
|
1428
|
+
|
|
1429
|
+
// Simulate human inspection of the reCAPTCHA
|
|
1430
|
+
if (this.humanBehaviorSimulator) {
|
|
1431
|
+
// Look around the page naturally
|
|
1432
|
+
await this.humanBehaviorSimulator.simulateReadingTime(page, 'body');
|
|
1433
|
+
|
|
1434
|
+
// Hover over the reCAPTCHA area
|
|
1435
|
+
try {
|
|
1436
|
+
const recaptchaBox = await page.$('.g-recaptcha, #recaptcha, [data-sitekey]');
|
|
1437
|
+
if (recaptchaBox) {
|
|
1438
|
+
const boundingBox = await recaptchaBox.boundingBox();
|
|
1439
|
+
if (boundingBox) {
|
|
1440
|
+
await this.humanBehaviorSimulator.simulateMouseMovement(
|
|
1441
|
+
page,
|
|
1442
|
+
boundingBox.x - 100,
|
|
1443
|
+
boundingBox.y - 100,
|
|
1444
|
+
boundingBox.x + boundingBox.width / 2,
|
|
1445
|
+
boundingBox.y + boundingBox.height / 2
|
|
1446
|
+
);
|
|
1447
|
+
await this.humanBehaviorSimulator.delay(2000, 0.4);
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
console.warn('reCAPTCHA interaction failed:', error.message);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
return true;
|
|
1456
|
+
}
|
|
1457
|
+
|
|
1458
|
+
return false;
|
|
1459
|
+
} catch (error) {
|
|
1460
|
+
console.warn('reCAPTCHA handling failed:', error.message);
|
|
1461
|
+
return false;
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
/**
|
|
1466
|
+
* Proxy rotation management
|
|
1467
|
+
*/
|
|
1468
|
+
async rotateProxy(config) {
|
|
1469
|
+
if (!config.proxyRotation?.enabled || !config.proxyRotation?.proxies?.length) {
|
|
1470
|
+
return null;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
const now = Date.now();
|
|
1474
|
+
const { rotationInterval, proxies } = config.proxyRotation;
|
|
1475
|
+
|
|
1476
|
+
if (now - this.proxyManager.lastRotation > rotationInterval) {
|
|
1477
|
+
this.proxyManager.proxyIndex = (this.proxyManager.proxyIndex + 1) % proxies.length;
|
|
1478
|
+
this.proxyManager.currentProxy = proxies[this.proxyManager.proxyIndex];
|
|
1479
|
+
this.proxyManager.lastRotation = now;
|
|
1480
|
+
|
|
1481
|
+
console.log('Rotated to proxy:', this.proxyManager.currentProxy);
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
return this.proxyManager.currentProxy;
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
/**
|
|
1488
|
+
* Create stealth page with anti-detection measures
|
|
1489
|
+
*/
|
|
1490
|
+
async createStealthPage(contextId) {
|
|
1491
|
+
const contextData = this.contexts.get(contextId);
|
|
1492
|
+
if (!contextData) {
|
|
1493
|
+
throw new Error('Context not found');
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
const page = await contextData.context.newPage();
|
|
1497
|
+
|
|
1498
|
+
// Apply additional page-level stealth measures
|
|
1499
|
+
await this.applyPageStealthMeasures(page, contextData.config, contextData.fingerprint);
|
|
1500
|
+
|
|
1501
|
+
return page;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/**
|
|
1505
|
+
* Apply page-level stealth measures
|
|
1506
|
+
*/
|
|
1507
|
+
async applyPageStealthMeasures(page, config, fingerprint) {
|
|
1508
|
+
// Enhanced resource blocking with stealth considerations
|
|
1509
|
+
await page.route('**/*', route => {
|
|
1510
|
+
const resourceType = route.request().resourceType();
|
|
1511
|
+
const url = route.request().url();
|
|
1512
|
+
|
|
1513
|
+
// Block known bot detection resources
|
|
1514
|
+
const blockedDomains = [
|
|
1515
|
+
'botd.fpjs.io',
|
|
1516
|
+
'challenges.cloudflare.com',
|
|
1517
|
+
'datadome.co',
|
|
1518
|
+
'perimeterx.net',
|
|
1519
|
+
'distilnetworks.com'
|
|
1520
|
+
];
|
|
1521
|
+
|
|
1522
|
+
if (blockedDomains.some(domain => url.includes(domain))) {
|
|
1523
|
+
route.abort();
|
|
1524
|
+
return;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
// Don't block detection-related resources that might be expected
|
|
1528
|
+
if (url.includes('webdriver') || url.includes('selenium') || url.includes('puppeteer')) {
|
|
1529
|
+
route.abort();
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
// Selective resource blocking based on level
|
|
1534
|
+
if (config.level === 'advanced') {
|
|
1535
|
+
if (['image', 'font', 'stylesheet'].includes(resourceType)) {
|
|
1536
|
+
// Allow some images/fonts to maintain realism
|
|
1537
|
+
if (Math.random() < 0.3) {
|
|
1538
|
+
route.continue();
|
|
1539
|
+
} else {
|
|
1540
|
+
route.abort();
|
|
1541
|
+
}
|
|
1542
|
+
} else {
|
|
1543
|
+
route.continue();
|
|
1544
|
+
}
|
|
1545
|
+
} else {
|
|
1546
|
+
route.continue();
|
|
1547
|
+
}
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
// Add request headers
|
|
1551
|
+
await page.setExtraHTTPHeaders(fingerprint.headers);
|
|
1552
|
+
|
|
1553
|
+
// Emulate realistic network conditions
|
|
1554
|
+
if (config.level === 'advanced') {
|
|
1555
|
+
const client = await page.context().newCDPSession(page);
|
|
1556
|
+
await client.send('Network.emulateNetworkConditions', {
|
|
1557
|
+
offline: false,
|
|
1558
|
+
downloadThroughput: (1.5 + Math.random() * 2) * 1024 * 1024 / 8, // 1.5-3.5 Mbps
|
|
1559
|
+
uploadThroughput: (0.75 + Math.random() * 1.25) * 1024 * 1024 / 8, // 0.75-2 Mbps
|
|
1560
|
+
latency: 40 + Math.random() * 60 // 40-100ms
|
|
1561
|
+
});
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
// Set up human behavior if enabled
|
|
1565
|
+
if (config.simulateHumanBehavior) {
|
|
1566
|
+
await this.initializeHumanBehaviorSimulator();
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
return page;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
/**
|
|
1573
|
+
* Simulate realistic mouse movements using Bezier curves
|
|
1574
|
+
*/
|
|
1575
|
+
async simulateRealisticMouseMovements(page) {
|
|
1576
|
+
if (!this.humanBehaviorSimulator) return;
|
|
1577
|
+
|
|
1578
|
+
const viewport = await page.viewportSize();
|
|
1579
|
+
const movements = Math.floor(Math.random() * 4) + 2; // 2-5 movements
|
|
1580
|
+
|
|
1581
|
+
let currentX = Math.random() * viewport.width;
|
|
1582
|
+
let currentY = Math.random() * viewport.height;
|
|
1583
|
+
|
|
1584
|
+
for (let i = 0; i < movements; i++) {
|
|
1585
|
+
const targetX = Math.random() * viewport.width;
|
|
1586
|
+
const targetY = Math.random() * viewport.height;
|
|
1587
|
+
|
|
1588
|
+
await this.humanBehaviorSimulator.simulateMouseMovement(
|
|
1589
|
+
page, currentX, currentY, targetX, targetY
|
|
1590
|
+
);
|
|
1591
|
+
|
|
1592
|
+
currentX = targetX;
|
|
1593
|
+
currentY = targetY;
|
|
1594
|
+
|
|
1595
|
+
await this.humanBehaviorSimulator.delay(300, 0.5);
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
/**
|
|
1600
|
+
* Simulate natural scrolling behavior
|
|
1601
|
+
*/
|
|
1602
|
+
async simulateNaturalScrolling(page) {
|
|
1603
|
+
if (!this.humanBehaviorSimulator) return;
|
|
1604
|
+
|
|
1605
|
+
// Random scroll behavior
|
|
1606
|
+
if (Math.random() < 0.7) { // 70% chance to scroll
|
|
1607
|
+
const direction = Math.random() < 0.8 ? 'down' : 'up';
|
|
1608
|
+
const distance = 100 + Math.random() * 300;
|
|
1609
|
+
const duration = 800 + Math.random() * 1200;
|
|
1610
|
+
|
|
1611
|
+
await this.humanBehaviorSimulator.simulateScroll(page, {
|
|
1612
|
+
direction,
|
|
1613
|
+
distance,
|
|
1614
|
+
duration
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
/**
|
|
1620
|
+
* Utility functions
|
|
1621
|
+
*/
|
|
1622
|
+
weightedRandom(weights) {
|
|
1623
|
+
const random = Math.random();
|
|
1624
|
+
let sum = 0;
|
|
1625
|
+
for (const [option, weight] of Object.entries(weights)) {
|
|
1626
|
+
sum += weight;
|
|
1627
|
+
if (random <= sum) {
|
|
1628
|
+
return option;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
return Object.keys(weights)[0];
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
weightedRandomFromArray(items) {
|
|
1635
|
+
const totalWeight = items.reduce((sum, item) => sum + (item.weight || 1), 0);
|
|
1636
|
+
let random = Math.random() * totalWeight;
|
|
1637
|
+
|
|
1638
|
+
for (const item of items) {
|
|
1639
|
+
random -= (item.weight || 1);
|
|
1640
|
+
if (random <= 0) {
|
|
1641
|
+
return item;
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1644
|
+
|
|
1645
|
+
return items[0];
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
randomFloat(min, max, decimals = 2) {
|
|
1649
|
+
return parseFloat((Math.random() * (max - min) + min).toFixed(decimals));
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
randomHex(length) {
|
|
1653
|
+
return Array.from({ length }, () => Math.floor(Math.random() * 16).toString(16)).join('');
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1656
|
+
generateContextId() {
|
|
1657
|
+
return 'stealth_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/**
|
|
1661
|
+
* Get context information
|
|
1662
|
+
*/
|
|
1663
|
+
getContextInfo(contextId) {
|
|
1664
|
+
const contextData = this.contexts.get(contextId);
|
|
1665
|
+
if (!contextData) {
|
|
1666
|
+
return null;
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
return {
|
|
1670
|
+
contextId,
|
|
1671
|
+
fingerprint: contextData.fingerprint,
|
|
1672
|
+
config: contextData.config,
|
|
1673
|
+
created: contextData.created || Date.now()
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
|
|
1677
|
+
/**
|
|
1678
|
+
* Close specific context
|
|
1679
|
+
*/
|
|
1680
|
+
async closeContext(contextId) {
|
|
1681
|
+
const contextData = this.contexts.get(contextId);
|
|
1682
|
+
if (contextData) {
|
|
1683
|
+
await contextData.context.close();
|
|
1684
|
+
this.contexts.delete(contextId);
|
|
1685
|
+
this.fingerprints.delete(contextId);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
/**
|
|
1690
|
+
* Close all contexts and browser
|
|
1691
|
+
*/
|
|
1692
|
+
async cleanup() {
|
|
1693
|
+
// Close all contexts
|
|
1694
|
+
for (const [contextId, contextData] of this.contexts.entries()) {
|
|
1695
|
+
try {
|
|
1696
|
+
await contextData.context.close();
|
|
1697
|
+
} catch (error) {
|
|
1698
|
+
console.warn(`Failed to close context ${contextId}:`, error.message);
|
|
1699
|
+
}
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
this.contexts.clear();
|
|
1703
|
+
this.fingerprints.clear();
|
|
1704
|
+
|
|
1705
|
+
// Reset human behavior simulator
|
|
1706
|
+
if (this.humanBehaviorSimulator) {
|
|
1707
|
+
this.humanBehaviorSimulator.resetStats();
|
|
1708
|
+
this.humanBehaviorSimulator = null;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
// Close browser
|
|
1712
|
+
if (this.browser) {
|
|
1713
|
+
try {
|
|
1714
|
+
await this.browser.close();
|
|
1715
|
+
} catch (error) {
|
|
1716
|
+
console.warn('Failed to close browser:', error.message);
|
|
1717
|
+
}
|
|
1718
|
+
this.browser = null;
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
/**
|
|
1723
|
+
* Get comprehensive statistics
|
|
1724
|
+
*/
|
|
1725
|
+
getStats() {
|
|
1726
|
+
return {
|
|
1727
|
+
activeContexts: this.contexts.size,
|
|
1728
|
+
totalFingerprintsSaved: this.fingerprints.size,
|
|
1729
|
+
browserRunning: !!this.browser,
|
|
1730
|
+
humanBehaviorActive: !!this.humanBehaviorSimulator,
|
|
1731
|
+
performanceMetrics: this.performanceMetrics,
|
|
1732
|
+
proxyStatus: {
|
|
1733
|
+
enabled: this.proxyManager.activeProxies.length > 0,
|
|
1734
|
+
currentProxy: this.proxyManager.currentProxy,
|
|
1735
|
+
totalProxies: this.proxyManager.activeProxies.length
|
|
1736
|
+
},
|
|
1737
|
+
bypassCacheSize: this.bypassCache.size,
|
|
1738
|
+
canvasCacheSize: this.canvasCache.size
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
/**
|
|
1743
|
+
* Validate stealth configuration
|
|
1744
|
+
*/
|
|
1745
|
+
validateConfig(config) {
|
|
1746
|
+
try {
|
|
1747
|
+
return StealthConfigSchema.parse(config);
|
|
1748
|
+
} catch (error) {
|
|
1749
|
+
throw new Error(`Invalid stealth configuration: ${error.message}`);
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
/**
|
|
1754
|
+
* Get the stealth configuration schema
|
|
1755
|
+
*/
|
|
1756
|
+
getStealthConfigSchema() {
|
|
1757
|
+
return StealthConfigSchema;
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Update performance metrics
|
|
1762
|
+
*/
|
|
1763
|
+
updatePerformanceMetrics(metric, value) {
|
|
1764
|
+
if (this.performanceMetrics.hasOwnProperty(metric)) {
|
|
1765
|
+
this.performanceMetrics[metric] = value;
|
|
1766
|
+
}
|
|
1767
|
+
}
|
|
1768
|
+
|
|
1769
|
+
/**
|
|
1770
|
+
* Clear bypass cache
|
|
1771
|
+
*/
|
|
1772
|
+
clearBypassCache() {
|
|
1773
|
+
this.bypassCache.clear();
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
/**
|
|
1777
|
+
* Enable stealth mode with specified level
|
|
1778
|
+
*/
|
|
1779
|
+
enableStealthMode(level = 'medium') {
|
|
1780
|
+
this.defaultConfig.level = level;
|
|
1781
|
+
this.defaultConfig.randomizeFingerprint = true;
|
|
1782
|
+
this.defaultConfig.simulateHumanBehavior = true;
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
/**
|
|
1786
|
+
* Disable stealth mode
|
|
1787
|
+
*/
|
|
1788
|
+
disableStealthMode() {
|
|
1789
|
+
this.defaultConfig.level = 'basic';
|
|
1790
|
+
this.defaultConfig.randomizeFingerprint = false;
|
|
1791
|
+
this.defaultConfig.simulateHumanBehavior = false;
|
|
1792
|
+
}
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
export default StealthBrowserManager;
|