@fanboynz/network-scanner 1.0.37 → 1.0.38
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/lib/cloudflare.js +245 -46
- package/nwss.js +4 -4
- package/package.json +1 -1
package/lib/cloudflare.js
CHANGED
|
@@ -1,8 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cloudflare bypass and challenge handling module -
|
|
2
|
+
* Cloudflare bypass and challenge handling module - Optimized with smart detection and adaptive timeouts
|
|
3
|
+
* Version: 2.1.0 - Enhanced with quick detection, adaptive timeouts, and comprehensive debug logging
|
|
3
4
|
* Handles phishing warnings, Turnstile challenges, and modern Cloudflare protections
|
|
4
5
|
*/
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Module version information
|
|
9
|
+
*/
|
|
10
|
+
const CLOUDFLARE_MODULE_VERSION = '2.1.0';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Gets module version information
|
|
14
|
+
* @returns {object} Version information object
|
|
15
|
+
*/
|
|
16
|
+
function getModuleInfo() {
|
|
17
|
+
return {
|
|
18
|
+
version: CLOUDFLARE_MODULE_VERSION,
|
|
19
|
+
name: 'Cloudflare Protection Handler'
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
6
23
|
/**
|
|
7
24
|
* Cross-version compatible timeout function for Puppeteer with timeout protection
|
|
8
25
|
*/
|
|
@@ -86,7 +103,61 @@ async function safeWaitForNavigation(page, timeout = 15000) {
|
|
|
86
103
|
}
|
|
87
104
|
|
|
88
105
|
/**
|
|
89
|
-
*
|
|
106
|
+
* Quick Cloudflare detection - faster initial check to avoid unnecessary waiting
|
|
107
|
+
*/
|
|
108
|
+
async function quickCloudflareDetection(page, forceDebug = false) {
|
|
109
|
+
try {
|
|
110
|
+
const quickCheck = await safePageEvaluate(page, () => {
|
|
111
|
+
const title = document.title || '';
|
|
112
|
+
const bodyText = document.body ? document.body.textContent.substring(0, 500) : '';
|
|
113
|
+
const url = window.location.href;
|
|
114
|
+
|
|
115
|
+
// Quick indicators of Cloudflare presence
|
|
116
|
+
const hasCloudflareIndicators =
|
|
117
|
+
title.includes('Just a moment') ||
|
|
118
|
+
title.includes('Checking your browser') ||
|
|
119
|
+
title.includes('Attention Required') ||
|
|
120
|
+
bodyText.includes('Cloudflare') ||
|
|
121
|
+
bodyText.includes('cf-ray') ||
|
|
122
|
+
bodyText.includes('Verify you are human') ||
|
|
123
|
+
bodyText.includes('This website has been reported for potential phishing') ||
|
|
124
|
+
bodyText.includes('Please wait while we verify') ||
|
|
125
|
+
url.includes('/cdn-cgi/challenge-platform/') ||
|
|
126
|
+
url.includes('cloudflare.com') ||
|
|
127
|
+
document.querySelector('[data-ray]') ||
|
|
128
|
+
document.querySelector('[data-cf-challenge]') ||
|
|
129
|
+
document.querySelector('.cf-challenge-running') ||
|
|
130
|
+
document.querySelector('.cf-challenge-container') ||
|
|
131
|
+
document.querySelector('.cf-turnstile') ||
|
|
132
|
+
document.querySelector('.ctp-checkbox-container') ||
|
|
133
|
+
document.querySelector('iframe[src*="challenges.cloudflare.com"]') ||
|
|
134
|
+
document.querySelector('iframe[title*="Cloudflare security challenge"]') ||
|
|
135
|
+
document.querySelector('script[src*="/cdn-cgi/challenge-platform/"]') ||
|
|
136
|
+
document.querySelector('a[href*="continue"]');
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
hasIndicators: hasCloudflareIndicators,
|
|
140
|
+
title,
|
|
141
|
+
url,
|
|
142
|
+
bodySnippet: bodyText.substring(0, 200)
|
|
143
|
+
};
|
|
144
|
+
}, 3000); // Quick 3-second timeout
|
|
145
|
+
|
|
146
|
+
if (forceDebug && quickCheck.hasIndicators) {
|
|
147
|
+
console.log(`[debug][cloudflare] Quick detection found Cloudflare indicators on ${quickCheck.url}`);
|
|
148
|
+
} else if (forceDebug && !quickCheck.hasIndicators) {
|
|
149
|
+
console.log(`[debug][cloudflare] Quick detection found no Cloudflare indicators on ${quickCheck.url}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return quickCheck;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if (forceDebug) console.log(`[debug][cloudflare] Quick detection failed: ${error.message}`);
|
|
155
|
+
return { hasIndicators: false, error: error.message };
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Analyzes the current page to detect Cloudflare challenges - Enhanced with timeout protection and detailed debug logging
|
|
90
161
|
*/
|
|
91
162
|
async function analyzeCloudflareChallenge(page) {
|
|
92
163
|
try {
|
|
@@ -161,7 +232,7 @@ async function analyzeCloudflareChallenge(page) {
|
|
|
161
232
|
url: window.location.href,
|
|
162
233
|
bodySnippet: bodyText.substring(0, 200)
|
|
163
234
|
};
|
|
164
|
-
},
|
|
235
|
+
}, 8000); // Reduced from 10 to 8 seconds
|
|
165
236
|
} catch (error) {
|
|
166
237
|
return {
|
|
167
238
|
isChallengePresent: false,
|
|
@@ -175,7 +246,7 @@ async function analyzeCloudflareChallenge(page) {
|
|
|
175
246
|
}
|
|
176
247
|
|
|
177
248
|
/**
|
|
178
|
-
* Handles Cloudflare phishing warnings with timeout protection
|
|
249
|
+
* Handles Cloudflare phishing warnings with timeout protection and enhanced debug logging
|
|
179
250
|
*/
|
|
180
251
|
async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
181
252
|
const result = {
|
|
@@ -198,13 +269,16 @@ async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
|
198
269
|
result.details = challengeInfo;
|
|
199
270
|
|
|
200
271
|
if (forceDebug) {
|
|
201
|
-
console.log(`[debug][cloudflare] Phishing warning detected on ${currentUrl}
|
|
272
|
+
console.log(`[debug][cloudflare] Phishing warning detected on ${currentUrl}:`);
|
|
273
|
+
console.log(`[debug][cloudflare] Page Title: "${challengeInfo.title}"`);
|
|
274
|
+
console.log(`[debug][cloudflare] Current URL: ${challengeInfo.url}`);
|
|
275
|
+
console.log(`[debug][cloudflare] Body snippet: ${challengeInfo.bodySnippet}`);
|
|
202
276
|
}
|
|
203
277
|
|
|
204
278
|
try {
|
|
205
279
|
// Use safe click with shorter timeout
|
|
206
280
|
await safeClick(page, 'a[href*="continue"]', 3000);
|
|
207
|
-
await safeWaitForNavigation(page,
|
|
281
|
+
await safeWaitForNavigation(page, 8000);
|
|
208
282
|
|
|
209
283
|
result.success = true;
|
|
210
284
|
if (forceDebug) console.log(`[debug][cloudflare] Successfully bypassed phishing warning for ${currentUrl}`);
|
|
@@ -225,7 +299,7 @@ async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
|
225
299
|
}
|
|
226
300
|
|
|
227
301
|
/**
|
|
228
|
-
* Attempts to solve Cloudflare challenges with timeout protection
|
|
302
|
+
* Attempts to solve Cloudflare challenges with timeout protection and enhanced debug logging
|
|
229
303
|
*/
|
|
230
304
|
async function handleVerificationChallenge(page, currentUrl, forceDebug = false) {
|
|
231
305
|
const result = {
|
|
@@ -233,14 +307,15 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
233
307
|
attempted: false,
|
|
234
308
|
error: null,
|
|
235
309
|
details: null,
|
|
236
|
-
requiresHuman: false
|
|
310
|
+
requiresHuman: false,
|
|
311
|
+
method: null
|
|
237
312
|
};
|
|
238
313
|
|
|
239
314
|
try {
|
|
240
315
|
if (forceDebug) console.log(`[debug][cloudflare] Checking for verification challenge on ${currentUrl}`);
|
|
241
316
|
|
|
242
|
-
//
|
|
243
|
-
await waitForTimeout(page,
|
|
317
|
+
// Reduced wait time
|
|
318
|
+
await waitForTimeout(page, 1000);
|
|
244
319
|
|
|
245
320
|
const challengeInfo = await analyzeCloudflareChallenge(page);
|
|
246
321
|
result.details = challengeInfo;
|
|
@@ -249,7 +324,20 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
249
324
|
result.attempted = true;
|
|
250
325
|
|
|
251
326
|
if (forceDebug) {
|
|
252
|
-
console.log(`[debug][cloudflare] Challenge detected on ${currentUrl}
|
|
327
|
+
console.log(`[debug][cloudflare] Challenge detected on ${currentUrl}:`);
|
|
328
|
+
console.log(`[debug][cloudflare] Page Title: "${challengeInfo.title}"`);
|
|
329
|
+
console.log(`[debug][cloudflare] Current URL: ${challengeInfo.url}`);
|
|
330
|
+
console.log(`[debug][cloudflare] Is Turnstile: ${challengeInfo.isTurnstile}`);
|
|
331
|
+
console.log(`[debug][cloudflare] Is JS Challenge: ${challengeInfo.isJSChallenge}`);
|
|
332
|
+
console.log(`[debug][cloudflare] Has Legacy Checkbox: ${challengeInfo.hasLegacyCheckbox}`);
|
|
333
|
+
console.log(`[debug][cloudflare] Has Turnstile Iframe: ${challengeInfo.hasTurnstileIframe}`);
|
|
334
|
+
console.log(`[debug][cloudflare] Has Turnstile Container: ${challengeInfo.hasTurnstileContainer}`);
|
|
335
|
+
console.log(`[debug][cloudflare] Has Turnstile Checkbox: ${challengeInfo.hasTurnstileCheckbox}`);
|
|
336
|
+
console.log(`[debug][cloudflare] Has CAPTCHA: ${challengeInfo.hasCaptcha}`);
|
|
337
|
+
console.log(`[debug][cloudflare] Has Challenge Running: ${challengeInfo.hasChallengeRunning}`);
|
|
338
|
+
console.log(`[debug][cloudflare] Has Data Ray: ${challengeInfo.hasDataRay}`);
|
|
339
|
+
console.log(`[debug][cloudflare] Has Turnstile Response: ${challengeInfo.hasTurnstileResponse}`);
|
|
340
|
+
console.log(`[debug][cloudflare] Body snippet: ${challengeInfo.bodySnippet}`);
|
|
253
341
|
}
|
|
254
342
|
|
|
255
343
|
// Check for CAPTCHA that requires human intervention
|
|
@@ -264,6 +352,7 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
264
352
|
const solveResult = await attemptChallengeSolveWithTimeout(page, currentUrl, challengeInfo, forceDebug);
|
|
265
353
|
result.success = solveResult.success;
|
|
266
354
|
result.error = solveResult.error;
|
|
355
|
+
result.method = solveResult.method;
|
|
267
356
|
|
|
268
357
|
} else {
|
|
269
358
|
if (forceDebug) console.log(`[debug][cloudflare] No verification challenge detected on ${currentUrl}`);
|
|
@@ -288,11 +377,11 @@ async function attemptChallengeSolveWithTimeout(page, currentUrl, challengeInfo,
|
|
|
288
377
|
};
|
|
289
378
|
|
|
290
379
|
try {
|
|
291
|
-
//
|
|
380
|
+
// Reduced timeout for challenge solving
|
|
292
381
|
return await Promise.race([
|
|
293
382
|
attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug),
|
|
294
383
|
new Promise((_, reject) =>
|
|
295
|
-
setTimeout(() => reject(new Error('Challenge solving timeout')),
|
|
384
|
+
setTimeout(() => reject(new Error('Challenge solving timeout')), 20000)
|
|
296
385
|
)
|
|
297
386
|
]);
|
|
298
387
|
} catch (error) {
|
|
@@ -303,7 +392,7 @@ async function attemptChallengeSolveWithTimeout(page, currentUrl, challengeInfo,
|
|
|
303
392
|
}
|
|
304
393
|
|
|
305
394
|
/**
|
|
306
|
-
* Attempts to solve a Cloudflare challenge with modern techniques
|
|
395
|
+
* Attempts to solve a Cloudflare challenge with modern techniques and enhanced debug logging
|
|
307
396
|
*/
|
|
308
397
|
async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug = false) {
|
|
309
398
|
const result = {
|
|
@@ -325,7 +414,7 @@ async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug
|
|
|
325
414
|
return result;
|
|
326
415
|
}
|
|
327
416
|
} catch (jsError) {
|
|
328
|
-
if (forceDebug) console.log(`[debug][cloudflare] JS challenge wait
|
|
417
|
+
if (forceDebug) console.log(`[debug][cloudflare] JS challenge wait failed for ${currentUrl}: ${jsError.message}`);
|
|
329
418
|
}
|
|
330
419
|
}
|
|
331
420
|
|
|
@@ -342,7 +431,7 @@ async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug
|
|
|
342
431
|
return result;
|
|
343
432
|
}
|
|
344
433
|
} catch (turnstileError) {
|
|
345
|
-
if (forceDebug) console.log(`[debug][cloudflare] Turnstile method
|
|
434
|
+
if (forceDebug) console.log(`[debug][cloudflare] Turnstile method failed for ${currentUrl}: ${turnstileError.message}`);
|
|
346
435
|
}
|
|
347
436
|
}
|
|
348
437
|
|
|
@@ -359,7 +448,7 @@ async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug
|
|
|
359
448
|
return result;
|
|
360
449
|
}
|
|
361
450
|
} catch (legacyError) {
|
|
362
|
-
if (forceDebug) console.log(`[debug][cloudflare] Legacy checkbox method
|
|
451
|
+
if (forceDebug) console.log(`[debug][cloudflare] Legacy checkbox method failed for ${currentUrl}: ${legacyError.message}`);
|
|
363
452
|
}
|
|
364
453
|
}
|
|
365
454
|
|
|
@@ -371,7 +460,7 @@ async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug
|
|
|
371
460
|
}
|
|
372
461
|
|
|
373
462
|
/**
|
|
374
|
-
* Waits for JS challenge completion with timeout protection
|
|
463
|
+
* Waits for JS challenge completion with timeout protection and enhanced debug logging
|
|
375
464
|
*/
|
|
376
465
|
async function waitForJSChallengeCompletion(page, forceDebug = false) {
|
|
377
466
|
const result = {
|
|
@@ -382,7 +471,7 @@ async function waitForJSChallengeCompletion(page, forceDebug = false) {
|
|
|
382
471
|
try {
|
|
383
472
|
if (forceDebug) console.log(`[debug][cloudflare] Waiting for JS challenge completion`);
|
|
384
473
|
|
|
385
|
-
//
|
|
474
|
+
// Reduced timeout for JS challenge completion
|
|
386
475
|
await Promise.race([
|
|
387
476
|
page.waitForFunction(
|
|
388
477
|
() => {
|
|
@@ -391,23 +480,25 @@ async function waitForJSChallengeCompletion(page, forceDebug = false) {
|
|
|
391
480
|
!document.querySelector('.cf-challenge-running') &&
|
|
392
481
|
!document.querySelector('[data-cf-challenge]');
|
|
393
482
|
},
|
|
394
|
-
{ timeout:
|
|
483
|
+
{ timeout: 15000 }
|
|
395
484
|
),
|
|
396
485
|
new Promise((_, reject) =>
|
|
397
|
-
setTimeout(() => reject(new Error('JS challenge timeout')),
|
|
486
|
+
setTimeout(() => reject(new Error('JS challenge timeout')), 18000)
|
|
398
487
|
)
|
|
399
488
|
]);
|
|
400
489
|
|
|
401
490
|
result.success = true;
|
|
491
|
+
if (forceDebug) console.log(`[debug][cloudflare] JS challenge completed automatically`);
|
|
402
492
|
} catch (error) {
|
|
403
493
|
result.error = `JS challenge timeout: ${error.message}`;
|
|
494
|
+
if (forceDebug) console.log(`[debug][cloudflare] JS challenge wait failed: ${error.message}`);
|
|
404
495
|
}
|
|
405
496
|
|
|
406
497
|
return result;
|
|
407
498
|
}
|
|
408
499
|
|
|
409
500
|
/**
|
|
410
|
-
* Handles modern Turnstile challenges with timeout protection
|
|
501
|
+
* Handles modern Turnstile challenges with timeout protection and enhanced debug logging
|
|
411
502
|
*/
|
|
412
503
|
async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
413
504
|
const result = {
|
|
@@ -416,8 +507,8 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
416
507
|
};
|
|
417
508
|
|
|
418
509
|
try {
|
|
419
|
-
//
|
|
420
|
-
const turnstileTimeout =
|
|
510
|
+
// Reduced timeout for Turnstile operations
|
|
511
|
+
const turnstileTimeout = 8000; // Reduced from 10 to 8 seconds
|
|
421
512
|
|
|
422
513
|
const turnstileSelectors = [
|
|
423
514
|
'iframe[src*="challenges.cloudflare.com"]',
|
|
@@ -429,8 +520,8 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
429
520
|
for (const selector of turnstileSelectors) {
|
|
430
521
|
try {
|
|
431
522
|
await Promise.race([
|
|
432
|
-
page.waitForSelector(selector, { timeout:
|
|
433
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Selector timeout')),
|
|
523
|
+
page.waitForSelector(selector, { timeout: 2000 }),
|
|
524
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Selector timeout')), 2500))
|
|
434
525
|
]);
|
|
435
526
|
|
|
436
527
|
const frames = await page.frames();
|
|
@@ -438,14 +529,20 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
438
529
|
frame.url().includes('challenges.cloudflare.com') ||
|
|
439
530
|
frame.url().includes('turnstile')
|
|
440
531
|
);
|
|
441
|
-
if (turnstileFrame)
|
|
532
|
+
if (turnstileFrame) {
|
|
533
|
+
if (forceDebug) console.log(`[debug][cloudflare] Found Turnstile iframe using selector: ${selector}`);
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
442
536
|
} catch (e) {
|
|
537
|
+
if (forceDebug) console.log(`[debug][cloudflare] Selector ${selector} not found or timed out`);
|
|
443
538
|
continue;
|
|
444
539
|
}
|
|
445
540
|
}
|
|
446
541
|
|
|
447
542
|
if (turnstileFrame) {
|
|
448
|
-
if (forceDebug)
|
|
543
|
+
if (forceDebug) {
|
|
544
|
+
console.log(`[debug][cloudflare] Found Turnstile iframe with URL: ${turnstileFrame.url()}`);
|
|
545
|
+
}
|
|
449
546
|
|
|
450
547
|
const checkboxSelectors = [
|
|
451
548
|
'input[type="checkbox"].ctp-checkbox',
|
|
@@ -457,8 +554,8 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
457
554
|
for (const selector of checkboxSelectors) {
|
|
458
555
|
try {
|
|
459
556
|
await Promise.race([
|
|
460
|
-
turnstileFrame.waitForSelector(selector, { timeout:
|
|
461
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Checkbox timeout')),
|
|
557
|
+
turnstileFrame.waitForSelector(selector, { timeout: 2000 }),
|
|
558
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Checkbox timeout')), 2500))
|
|
462
559
|
]);
|
|
463
560
|
|
|
464
561
|
await waitForTimeout(page, 500);
|
|
@@ -467,36 +564,75 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
467
564
|
if (forceDebug) console.log(`[debug][cloudflare] Clicked Turnstile checkbox: ${selector}`);
|
|
468
565
|
break;
|
|
469
566
|
} catch (e) {
|
|
567
|
+
if (forceDebug) console.log(`[debug][cloudflare] Checkbox selector ${selector} not found or failed to click`);
|
|
470
568
|
continue;
|
|
471
569
|
}
|
|
472
570
|
}
|
|
473
571
|
|
|
474
|
-
// Wait for Turnstile completion with timeout
|
|
572
|
+
// Wait for Turnstile completion with reduced timeout
|
|
475
573
|
await Promise.race([
|
|
476
574
|
page.waitForFunction(
|
|
477
575
|
() => {
|
|
478
576
|
const responseInput = document.querySelector('input[name="cf-turnstile-response"]');
|
|
479
577
|
return responseInput && responseInput.value && responseInput.value.length > 0;
|
|
480
578
|
},
|
|
481
|
-
{ timeout:
|
|
579
|
+
{ timeout: 12000 }
|
|
482
580
|
),
|
|
483
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Turnstile completion timeout')),
|
|
581
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Turnstile completion timeout')), 15000))
|
|
484
582
|
]);
|
|
485
583
|
|
|
584
|
+
if (forceDebug) console.log(`[debug][cloudflare] Turnstile response token generated successfully`);
|
|
486
585
|
result.success = true;
|
|
487
586
|
} else {
|
|
488
|
-
|
|
587
|
+
// Try container-based Turnstile (non-iframe)
|
|
588
|
+
if (forceDebug) console.log(`[debug][cloudflare] No Turnstile iframe found, trying container-based approach`);
|
|
589
|
+
|
|
590
|
+
const containerSelectors = [
|
|
591
|
+
'.cf-turnstile',
|
|
592
|
+
'.ctp-checkbox-container',
|
|
593
|
+
'.ctp-checkbox-label'
|
|
594
|
+
];
|
|
595
|
+
|
|
596
|
+
for (const selector of containerSelectors) {
|
|
597
|
+
try {
|
|
598
|
+
await Promise.race([
|
|
599
|
+
page.waitForSelector(selector, { timeout: 2000 }),
|
|
600
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Container timeout')), 2500))
|
|
601
|
+
]);
|
|
602
|
+
|
|
603
|
+
await waitForTimeout(page, 500);
|
|
604
|
+
await page.click(selector);
|
|
605
|
+
|
|
606
|
+
if (forceDebug) console.log(`[debug][cloudflare] Clicked Turnstile container: ${selector}`);
|
|
607
|
+
|
|
608
|
+
const completionCheck = await checkChallengeCompletion(page);
|
|
609
|
+
if (completionCheck.isCompleted) {
|
|
610
|
+
result.success = true;
|
|
611
|
+
if (forceDebug) console.log(`[debug][cloudflare] Container-based Turnstile completed successfully`);
|
|
612
|
+
break;
|
|
613
|
+
}
|
|
614
|
+
} catch (e) {
|
|
615
|
+
if (forceDebug) console.log(`[debug][cloudflare] Container selector ${selector} not found or failed`);
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (!result.success) {
|
|
621
|
+
result.error = 'Turnstile iframe/container not found or not interactive';
|
|
622
|
+
if (forceDebug) console.log(`[debug][cloudflare] ${result.error}`);
|
|
623
|
+
}
|
|
489
624
|
}
|
|
490
625
|
|
|
491
626
|
} catch (error) {
|
|
492
627
|
result.error = `Turnstile handling failed: ${error.message}`;
|
|
628
|
+
if (forceDebug) console.log(`[debug][cloudflare] Turnstile handling error: ${error.message}`);
|
|
493
629
|
}
|
|
494
630
|
|
|
495
631
|
return result;
|
|
496
632
|
}
|
|
497
633
|
|
|
498
634
|
/**
|
|
499
|
-
* Handles legacy checkbox challenges with timeout protection
|
|
635
|
+
* Handles legacy checkbox challenges with timeout protection and enhanced debug logging
|
|
500
636
|
*/
|
|
501
637
|
async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
502
638
|
const result = {
|
|
@@ -505,6 +641,8 @@ async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
|
505
641
|
};
|
|
506
642
|
|
|
507
643
|
try {
|
|
644
|
+
if (forceDebug) console.log(`[debug][cloudflare] Attempting legacy checkbox challenge`);
|
|
645
|
+
|
|
508
646
|
const legacySelectors = [
|
|
509
647
|
'input[type="checkbox"]#challenge-form',
|
|
510
648
|
'input[type="checkbox"][name="cf_captcha_kind"]',
|
|
@@ -514,8 +652,8 @@ async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
|
514
652
|
for (const selector of legacySelectors) {
|
|
515
653
|
try {
|
|
516
654
|
await Promise.race([
|
|
517
|
-
page.waitForSelector(selector, { timeout:
|
|
518
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('Legacy selector timeout')),
|
|
655
|
+
page.waitForSelector(selector, { timeout: 2000 }),
|
|
656
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Legacy selector timeout')), 2500))
|
|
519
657
|
]);
|
|
520
658
|
|
|
521
659
|
const checkbox = await page.$(selector);
|
|
@@ -526,27 +664,31 @@ async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
|
526
664
|
const completionCheck = await checkChallengeCompletion(page);
|
|
527
665
|
if (completionCheck.isCompleted) {
|
|
528
666
|
result.success = true;
|
|
667
|
+
if (forceDebug) console.log(`[debug][cloudflare] Legacy checkbox challenge completed successfully`);
|
|
529
668
|
break;
|
|
530
669
|
}
|
|
531
670
|
}
|
|
532
671
|
} catch (e) {
|
|
672
|
+
if (forceDebug) console.log(`[debug][cloudflare] Legacy selector ${selector} failed: ${e.message}`);
|
|
533
673
|
continue;
|
|
534
674
|
}
|
|
535
675
|
}
|
|
536
676
|
|
|
537
677
|
if (!result.success) {
|
|
538
678
|
result.error = 'No interactive legacy checkbox found';
|
|
679
|
+
if (forceDebug) console.log(`[debug][cloudflare] ${result.error}`);
|
|
539
680
|
}
|
|
540
681
|
|
|
541
682
|
} catch (error) {
|
|
542
683
|
result.error = `Legacy checkbox handling failed: ${error.message}`;
|
|
684
|
+
if (forceDebug) console.log(`[debug][cloudflare] Legacy checkbox error: ${error.message}`);
|
|
543
685
|
}
|
|
544
686
|
|
|
545
687
|
return result;
|
|
546
688
|
}
|
|
547
689
|
|
|
548
690
|
/**
|
|
549
|
-
* Checks if challenge has been completed with timeout protection
|
|
691
|
+
* Checks if challenge has been completed with timeout protection and enhanced debug logging
|
|
550
692
|
*/
|
|
551
693
|
async function checkChallengeCompletion(page) {
|
|
552
694
|
try {
|
|
@@ -563,7 +705,7 @@ async function checkChallengeCompletion(page) {
|
|
|
563
705
|
return (noChallengeRunning && noChallengeContainer && noChallengePage) ||
|
|
564
706
|
hasClearanceCookie ||
|
|
565
707
|
hasTurnstileResponse;
|
|
566
|
-
},
|
|
708
|
+
}, 3000); // Reduced timeout
|
|
567
709
|
|
|
568
710
|
return { isCompleted };
|
|
569
711
|
} catch (error) {
|
|
@@ -572,9 +714,28 @@ async function checkChallengeCompletion(page) {
|
|
|
572
714
|
}
|
|
573
715
|
|
|
574
716
|
/**
|
|
575
|
-
* Main function to handle all Cloudflare challenges with
|
|
717
|
+
* Main function to handle all Cloudflare challenges with smart detection and adaptive timeouts
|
|
576
718
|
*/
|
|
577
719
|
async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDebug = false) {
|
|
720
|
+
if (forceDebug) {
|
|
721
|
+
console.log(`[debug][cloudflare] Using Cloudflare module v${CLOUDFLARE_MODULE_VERSION} for ${currentUrl}`);
|
|
722
|
+
}
|
|
723
|
+
// Quick detection first - exit early if no Cloudflare detected and no explicit config
|
|
724
|
+
const quickDetection = await quickCloudflareDetection(page, forceDebug);
|
|
725
|
+
|
|
726
|
+
// Only proceed if we have indicators OR explicit config enables Cloudflare handling
|
|
727
|
+
if (!quickDetection.hasIndicators && !siteConfig.cloudflare_phish && !siteConfig.cloudflare_bypass) {
|
|
728
|
+
if (forceDebug) console.log(`[debug][cloudflare] No Cloudflare indicators found and no explicit config, skipping protection handling for ${currentUrl}`);
|
|
729
|
+
if (forceDebug) console.log(`[debug][cloudflare] Quick detection details: title="${quickDetection.title}", bodySnippet="${quickDetection.bodySnippet}"`);
|
|
730
|
+
return {
|
|
731
|
+
phishingWarning: { attempted: false, success: true },
|
|
732
|
+
verificationChallenge: { attempted: false, success: true },
|
|
733
|
+
overallSuccess: true,
|
|
734
|
+
errors: [],
|
|
735
|
+
skippedNoIndicators: true
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
|
|
578
739
|
const result = {
|
|
579
740
|
phishingWarning: { attempted: false, success: false },
|
|
580
741
|
verificationChallenge: { attempted: false, success: false },
|
|
@@ -583,30 +744,45 @@ async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDeb
|
|
|
583
744
|
};
|
|
584
745
|
|
|
585
746
|
try {
|
|
586
|
-
//
|
|
747
|
+
// Adaptive timeout based on detection results and explicit config
|
|
748
|
+
let adaptiveTimeout;
|
|
749
|
+
if (siteConfig.cloudflare_phish || siteConfig.cloudflare_bypass) {
|
|
750
|
+
// Explicit config - give more time
|
|
751
|
+
adaptiveTimeout = quickDetection.hasIndicators ? 25000 : 20000;
|
|
752
|
+
} else {
|
|
753
|
+
// Auto-detected only - shorter timeout
|
|
754
|
+
adaptiveTimeout = quickDetection.hasIndicators ? 15000 : 10000;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
if (forceDebug) {
|
|
758
|
+
console.log(`[debug][cloudflare] Using adaptive timeout of ${adaptiveTimeout}ms for ${currentUrl} (indicators: ${quickDetection.hasIndicators}, explicit config: ${!!(siteConfig.cloudflare_phish || siteConfig.cloudflare_bypass)})`);
|
|
759
|
+
}
|
|
760
|
+
|
|
587
761
|
return await Promise.race([
|
|
588
762
|
performCloudflareHandling(page, currentUrl, siteConfig, forceDebug),
|
|
589
763
|
new Promise((resolve) => {
|
|
590
764
|
setTimeout(() => {
|
|
591
|
-
|
|
765
|
+
console.warn(`[cloudflare] Adaptive timeout (${adaptiveTimeout}ms) for ${currentUrl} - continuing with scan`);
|
|
592
766
|
resolve({
|
|
593
767
|
phishingWarning: { attempted: false, success: true },
|
|
594
768
|
verificationChallenge: { attempted: false, success: true },
|
|
595
769
|
overallSuccess: true,
|
|
596
|
-
errors: ['Cloudflare handling timed out']
|
|
770
|
+
errors: ['Cloudflare handling timed out'],
|
|
771
|
+
timedOut: true
|
|
597
772
|
});
|
|
598
|
-
},
|
|
773
|
+
}, adaptiveTimeout);
|
|
599
774
|
})
|
|
600
775
|
]);
|
|
601
776
|
} catch (error) {
|
|
602
777
|
result.overallSuccess = false;
|
|
603
778
|
result.errors.push(`Cloudflare handling failed: ${error.message}`);
|
|
779
|
+
if (forceDebug) console.log(`[debug][cloudflare] Overall handling failed: ${error.message}`);
|
|
604
780
|
return result;
|
|
605
781
|
}
|
|
606
782
|
}
|
|
607
783
|
|
|
608
784
|
/**
|
|
609
|
-
* Performs the actual Cloudflare handling
|
|
785
|
+
* Performs the actual Cloudflare handling with enhanced debug logging
|
|
610
786
|
*/
|
|
611
787
|
async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebug = false) {
|
|
612
788
|
const result = {
|
|
@@ -616,19 +792,30 @@ async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebu
|
|
|
616
792
|
errors: []
|
|
617
793
|
};
|
|
618
794
|
|
|
795
|
+
if (forceDebug) console.log(`[debug][cloudflare] Starting Cloudflare protection handling for ${currentUrl}`);
|
|
796
|
+
|
|
619
797
|
// Handle phishing warnings if enabled
|
|
620
798
|
if (siteConfig.cloudflare_phish === true) {
|
|
799
|
+
if (forceDebug) console.log(`[debug][cloudflare] Phishing warning bypass enabled for ${currentUrl}`);
|
|
800
|
+
|
|
621
801
|
const phishingResult = await handlePhishingWarning(page, currentUrl, forceDebug);
|
|
622
802
|
result.phishingWarning = phishingResult;
|
|
623
803
|
|
|
624
804
|
if (phishingResult.attempted && !phishingResult.success) {
|
|
625
805
|
result.overallSuccess = false;
|
|
626
806
|
result.errors.push(`Phishing warning bypass failed: ${phishingResult.error}`);
|
|
807
|
+
if (forceDebug) console.log(`[debug][cloudflare] Phishing warning handling failed: ${phishingResult.error}`);
|
|
808
|
+
} else if (phishingResult.attempted && phishingResult.success) {
|
|
809
|
+
if (forceDebug) console.log(`[debug][cloudflare] Phishing warning handled successfully`);
|
|
627
810
|
}
|
|
811
|
+
} else if (forceDebug) {
|
|
812
|
+
console.log(`[debug][cloudflare] Phishing warning bypass disabled for ${currentUrl}`);
|
|
628
813
|
}
|
|
629
814
|
|
|
630
815
|
// Handle verification challenges if enabled
|
|
631
816
|
if (siteConfig.cloudflare_bypass === true) {
|
|
817
|
+
if (forceDebug) console.log(`[debug][cloudflare] Challenge bypass enabled for ${currentUrl}`);
|
|
818
|
+
|
|
632
819
|
const challengeResult = await handleVerificationChallenge(page, currentUrl, forceDebug);
|
|
633
820
|
result.verificationChallenge = challengeResult;
|
|
634
821
|
|
|
@@ -636,12 +823,19 @@ async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebu
|
|
|
636
823
|
result.overallSuccess = false;
|
|
637
824
|
if (challengeResult.requiresHuman) {
|
|
638
825
|
result.errors.push(`Human intervention required: ${challengeResult.error}`);
|
|
826
|
+
if (forceDebug) console.log(`[debug][cloudflare] Human intervention required: ${challengeResult.error}`);
|
|
639
827
|
} else {
|
|
640
828
|
result.errors.push(`Challenge bypass failed: ${challengeResult.error}`);
|
|
829
|
+
if (forceDebug) console.log(`[debug][cloudflare] Challenge bypass failed: ${challengeResult.error}`);
|
|
641
830
|
}
|
|
831
|
+
} else if (challengeResult.attempted && challengeResult.success) {
|
|
832
|
+
if (forceDebug) console.log(`[debug][cloudflare] Challenge handled successfully using method: ${challengeResult.method || 'unknown'}`);
|
|
642
833
|
}
|
|
834
|
+
} else if (forceDebug) {
|
|
835
|
+
console.log(`[debug][cloudflare] Challenge bypass disabled for ${currentUrl}`);
|
|
643
836
|
}
|
|
644
837
|
|
|
838
|
+
// Log overall result
|
|
645
839
|
if (!result.overallSuccess && forceDebug) {
|
|
646
840
|
console.log(`[debug][cloudflare] Overall Cloudflare handling failed for ${currentUrl}:`);
|
|
647
841
|
result.errors.forEach(error => {
|
|
@@ -649,6 +843,8 @@ async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebu
|
|
|
649
843
|
});
|
|
650
844
|
} else if ((result.phishingWarning.attempted || result.verificationChallenge.attempted) && forceDebug) {
|
|
651
845
|
console.log(`[debug][cloudflare] Successfully handled Cloudflare protections for ${currentUrl}`);
|
|
846
|
+
} else if (forceDebug) {
|
|
847
|
+
console.log(`[debug][cloudflare] No Cloudflare protections detected or enabled for ${currentUrl}`);
|
|
652
848
|
}
|
|
653
849
|
|
|
654
850
|
return result;
|
|
@@ -663,5 +859,8 @@ module.exports = {
|
|
|
663
859
|
handleTurnstileChallenge,
|
|
664
860
|
waitForJSChallengeCompletion,
|
|
665
861
|
handleLegacyCheckbox,
|
|
666
|
-
checkChallengeCompletion
|
|
862
|
+
checkChallengeCompletion,
|
|
863
|
+
quickCloudflareDetection,
|
|
864
|
+
getModuleInfo,
|
|
865
|
+
CLOUDFLARE_MODULE_VERSION
|
|
667
866
|
};
|
package/nwss.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// === Network scanner script (nwss.js) v1.0.
|
|
1
|
+
// === Network scanner script (nwss.js) v1.0.38 ===
|
|
2
2
|
|
|
3
3
|
// puppeteer for browser automation, fs for file system operations, psl for domain parsing.
|
|
4
4
|
// const pLimit = require('p-limit'); // Will be dynamically imported
|
|
@@ -33,9 +33,9 @@ const { navigateWithRedirectHandling, handleRedirectTimeout } = require('./lib/r
|
|
|
33
33
|
const { monitorBrowserHealth, isBrowserHealthy } = require('./lib/browserhealth');
|
|
34
34
|
|
|
35
35
|
// --- Script Configuration & Constants ---
|
|
36
|
-
const VERSION = '1.0.
|
|
37
|
-
const MAX_CONCURRENT_SITES =
|
|
38
|
-
const RESOURCE_CLEANUP_INTERVAL =
|
|
36
|
+
const VERSION = '1.0.38'; // Script version
|
|
37
|
+
const MAX_CONCURRENT_SITES = 12;
|
|
38
|
+
const RESOURCE_CLEANUP_INTERVAL = 180; // Close browser and restart every N sites to free resources
|
|
39
39
|
|
|
40
40
|
// get startTime
|
|
41
41
|
const startTime = Date.now();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fanboynz/network-scanner",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.38",
|
|
4
4
|
"description": "A Puppeteer-based network scanner for analyzing web traffic, generating adblock filter rules, and identifying third-party requests. Features include fingerprint spoofing, Cloudflare bypass, content analysis with curl/grep, and multiple output formats.",
|
|
5
5
|
"main": "nwss.js",
|
|
6
6
|
"scripts": {
|