@fanboynz/network-scanner 1.0.80 → 1.0.82
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 +364 -110
- package/lib/colorize.js +10 -3
- package/nwss.js +153 -45
- package/package.json +1 -1
package/lib/cloudflare.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Cloudflare bypass and challenge handling module - Optimized with smart detection and adaptive timeouts
|
|
3
|
-
* Version: 2.
|
|
3
|
+
* Version: 2.4.0 - Fix possible endless loops with retry logic and loop detection
|
|
4
|
+
* Version: 2.3.1 - Colorize CF
|
|
5
|
+
* Version: 2.3.0 - Support CF iframe challenges, and better error handling
|
|
6
|
+
* Version: 2.2.0 - Enhanced with retry logic, caching, and improved error handling
|
|
7
|
+
* Version: 2.1.0 - Enhanced with quick detection, adaptive timeouts, and comprehensive debug logging
|
|
4
8
|
* Handles phishing warnings, Turnstile challenges, and modern Cloudflare protections
|
|
5
9
|
*/
|
|
6
10
|
|
|
11
|
+
// Import color utilities
|
|
12
|
+
const { formatLogMessage } = require('./colorize');
|
|
13
|
+
|
|
7
14
|
/**
|
|
8
15
|
* Module version information
|
|
9
16
|
*/
|
|
10
|
-
const CLOUDFLARE_MODULE_VERSION = '2.
|
|
17
|
+
const CLOUDFLARE_MODULE_VERSION = '2.4.0';
|
|
11
18
|
|
|
12
19
|
/**
|
|
13
20
|
* Timeout constants for various operations (in milliseconds)
|
|
@@ -62,6 +69,46 @@ const ERROR_TYPES = {
|
|
|
62
69
|
UNKNOWN: 'unknown'
|
|
63
70
|
};
|
|
64
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Gets the retry configuration for a site, merging site-specific and global settings
|
|
74
|
+
* @param {Object} siteConfig - Site configuration object
|
|
75
|
+
* @returns {Object} Merged retry configuration
|
|
76
|
+
*/
|
|
77
|
+
function getRetryConfig(siteConfig) {
|
|
78
|
+
return {
|
|
79
|
+
maxAttempts: siteConfig.cloudflare_max_retries || RETRY_CONFIG.maxAttempts,
|
|
80
|
+
baseDelay: RETRY_CONFIG.baseDelay,
|
|
81
|
+
maxDelay: RETRY_CONFIG.maxDelay,
|
|
82
|
+
backoffMultiplier: RETRY_CONFIG.backoffMultiplier,
|
|
83
|
+
retryableErrors: RETRY_CONFIG.retryableErrors,
|
|
84
|
+
retryOnError: siteConfig.cloudflare_retry_on_error !== false // Default to true
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Detects if we're in a challenge redirect loop by checking URL patterns
|
|
90
|
+
*/
|
|
91
|
+
function detectChallengeLoop(url, previousUrls = []) {
|
|
92
|
+
// Check if current URL contains challenge indicators and we've seen similar URLs
|
|
93
|
+
const isChallengeUrl = url.includes('/cdn-cgi/challenge-platform/') ||
|
|
94
|
+
url.includes('challenges.cloudflare.com') ||
|
|
95
|
+
url.includes('cf-ray');
|
|
96
|
+
|
|
97
|
+
if (!isChallengeUrl) return false;
|
|
98
|
+
|
|
99
|
+
// Check if we've seen this exact URL or very similar challenge URLs
|
|
100
|
+
const similarUrls = previousUrls.filter(prevUrl => {
|
|
101
|
+
if (prevUrl === url) return true; // Exact match
|
|
102
|
+
// Check for similar challenge URLs with different ray IDs
|
|
103
|
+
if (prevUrl.includes('/cdn-cgi/challenge-platform/') && url.includes('/cdn-cgi/challenge-platform/')) {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
return false;
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
return similarUrls.length >= 2; // Loop detected if we've seen similar URLs 2+ times
|
|
110
|
+
}
|
|
111
|
+
|
|
65
112
|
/**
|
|
66
113
|
* Retry configuration with exponential backoff
|
|
67
114
|
*/
|
|
@@ -165,7 +212,7 @@ function getModuleInfo() {
|
|
|
165
212
|
*/
|
|
166
213
|
function shouldProcessUrl(url, forceDebug = false) {
|
|
167
214
|
if (!url || typeof url !== 'string') {
|
|
168
|
-
if (forceDebug) console.log(`[
|
|
215
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `[url-validation] Skipping invalid URL: ${url}`));
|
|
169
216
|
return false;
|
|
170
217
|
}
|
|
171
218
|
|
|
@@ -180,7 +227,7 @@ function shouldProcessUrl(url, forceDebug = false) {
|
|
|
180
227
|
for (const pattern of skipPatterns) {
|
|
181
228
|
if (urlLower.startsWith(pattern)) {
|
|
182
229
|
if (forceDebug) {
|
|
183
|
-
console.log(`[
|
|
230
|
+
console.log(formatLogMessage('cloudflare', `[url-validation] Skipping ${pattern} URL: ${url.substring(0, 100)}${url.length > 100 ? '...' : ''}`));
|
|
184
231
|
}
|
|
185
232
|
return false;
|
|
186
233
|
}
|
|
@@ -189,7 +236,7 @@ function shouldProcessUrl(url, forceDebug = false) {
|
|
|
189
236
|
// Only process HTTP/HTTPS URLs
|
|
190
237
|
if (!urlLower.startsWith('http://') && !urlLower.startsWith('https://')) {
|
|
191
238
|
if (forceDebug) {
|
|
192
|
-
console.log(`[
|
|
239
|
+
console.log(formatLogMessage('cloudflare', `[url-validation] Skipping non-HTTP(S) URL: ${url.substring(0, 100)}${url.length > 100 ? '...' : ''}`));
|
|
193
240
|
}
|
|
194
241
|
return false;
|
|
195
242
|
}
|
|
@@ -257,7 +304,7 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
|
|
|
257
304
|
]);
|
|
258
305
|
|
|
259
306
|
if (forceDebug && attempt > 1) {
|
|
260
|
-
console.log(
|
|
307
|
+
console.log(formatLogMessage('cloudflare', `Page evaluation succeeded on attempt ${attempt}`));
|
|
261
308
|
}
|
|
262
309
|
|
|
263
310
|
return result;
|
|
@@ -266,7 +313,7 @@ async function safePageEvaluate(page, func, timeout = TIMEOUTS.PAGE_EVALUATION_S
|
|
|
266
313
|
const errorType = categorizeError(error);
|
|
267
314
|
|
|
268
315
|
if (forceDebug) {
|
|
269
|
-
console.warn(
|
|
316
|
+
console.warn(formatLogMessage('cloudflare', `Page evaluation failed (attempt ${attempt}/${maxRetries}): ${error.message} [${errorType}]`));
|
|
270
317
|
}
|
|
271
318
|
|
|
272
319
|
// Don't retry if error type is not retryable or if it's the last attempt
|
|
@@ -328,7 +375,7 @@ async function safeWaitForNavigation(page, timeout = TIMEOUTS.NAVIGATION_TIMEOUT
|
|
|
328
375
|
)
|
|
329
376
|
]);
|
|
330
377
|
} catch (error) {
|
|
331
|
-
console.warn(
|
|
378
|
+
console.warn(formatLogMessage('cloudflare', `Navigation wait failed: ${error.message}`));
|
|
332
379
|
// Don't throw - just continue
|
|
333
380
|
}
|
|
334
381
|
}
|
|
@@ -343,7 +390,7 @@ async function quickCloudflareDetection(page, forceDebug = false) {
|
|
|
343
390
|
|
|
344
391
|
if (!shouldProcessUrl(currentPageUrl, forceDebug)) {
|
|
345
392
|
if (forceDebug) {
|
|
346
|
-
console.log(
|
|
393
|
+
console.log(formatLogMessage('cloudflare', `Quick detection skipping non-HTTP(S) page: ${currentPageUrl}`));
|
|
347
394
|
}
|
|
348
395
|
return { hasIndicators: false, skippedInvalidUrl: true };
|
|
349
396
|
}
|
|
@@ -353,7 +400,7 @@ async function quickCloudflareDetection(page, forceDebug = false) {
|
|
|
353
400
|
if (cachedResult !== null) {
|
|
354
401
|
if (forceDebug) {
|
|
355
402
|
const stats = detectionCache.getStats();
|
|
356
|
-
console.log(
|
|
403
|
+
console.log(formatLogMessage('cloudflare', `Using cached detection result (cache hit rate: ${stats.hitRate})`));
|
|
357
404
|
}
|
|
358
405
|
return cachedResult;
|
|
359
406
|
}
|
|
@@ -405,19 +452,19 @@ async function quickCloudflareDetection(page, forceDebug = false) {
|
|
|
405
452
|
|
|
406
453
|
if (forceDebug) {
|
|
407
454
|
if (quickCheck.hasIndicators) {
|
|
408
|
-
console.log(
|
|
455
|
+
console.log(formatLogMessage('cloudflare', `Quick detection found Cloudflare indicators on ${quickCheck.url}`));
|
|
409
456
|
} else {
|
|
410
|
-
console.log(
|
|
457
|
+
console.log(formatLogMessage('cloudflare', `Quick detection found no Cloudflare indicators on ${quickCheck.url}`));
|
|
411
458
|
}
|
|
412
459
|
|
|
413
460
|
if (quickCheck.attempts && quickCheck.attempts > 1) {
|
|
414
|
-
console.log(
|
|
461
|
+
console.log(formatLogMessage('cloudflare', `Detection required ${quickCheck.attempts} attempts`));
|
|
415
462
|
}
|
|
416
463
|
}
|
|
417
464
|
|
|
418
465
|
return quickCheck;
|
|
419
466
|
} catch (error) {
|
|
420
|
-
if (forceDebug) console.log(
|
|
467
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Quick detection failed: ${error.message}`));
|
|
421
468
|
return { hasIndicators: false, error: error.message };
|
|
422
469
|
}
|
|
423
470
|
}
|
|
@@ -534,7 +581,7 @@ async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
|
534
581
|
};
|
|
535
582
|
|
|
536
583
|
try {
|
|
537
|
-
if (forceDebug) console.log(
|
|
584
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checking for phishing warning on ${currentUrl}`));
|
|
538
585
|
|
|
539
586
|
// Shorter wait with timeout protection
|
|
540
587
|
await waitForTimeout(page, FAST_TIMEOUTS.PHISHING_WAIT);
|
|
@@ -546,10 +593,10 @@ async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
|
546
593
|
result.details = challengeInfo;
|
|
547
594
|
|
|
548
595
|
if (forceDebug) {
|
|
549
|
-
console.log(
|
|
550
|
-
console.log(`
|
|
551
|
-
console.log(`
|
|
552
|
-
console.log(`
|
|
596
|
+
console.log(formatLogMessage('cloudflare', `Phishing warning detected on ${currentUrl}:`));
|
|
597
|
+
console.log(formatLogMessage('cloudflare', ` Page Title: "${challengeInfo.title}"`));
|
|
598
|
+
console.log(formatLogMessage('cloudflare', ` Current URL: ${challengeInfo.url}`));
|
|
599
|
+
console.log(formatLogMessage('cloudflare', ` Body snippet: ${challengeInfo.bodySnippet}`));
|
|
553
600
|
}
|
|
554
601
|
|
|
555
602
|
try {
|
|
@@ -558,18 +605,18 @@ async function handlePhishingWarning(page, currentUrl, forceDebug = false) {
|
|
|
558
605
|
await safeWaitForNavigation(page, TIMEOUTS.PHISHING_NAVIGATION);
|
|
559
606
|
|
|
560
607
|
result.success = true;
|
|
561
|
-
if (forceDebug) console.log(
|
|
608
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Successfully bypassed phishing warning for ${currentUrl}`));
|
|
562
609
|
} catch (clickError) {
|
|
563
610
|
result.error = `Failed to click continue button: ${clickError.message}`;
|
|
564
|
-
if (forceDebug) console.log(
|
|
611
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Failed to bypass phishing warning: ${clickError.message}`));
|
|
565
612
|
}
|
|
566
613
|
} else {
|
|
567
|
-
if (forceDebug) console.log(
|
|
614
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `No phishing warning detected on ${currentUrl}`));
|
|
568
615
|
result.success = true; // No warning to handle
|
|
569
616
|
}
|
|
570
617
|
} catch (error) {
|
|
571
618
|
result.error = error.message;
|
|
572
|
-
if (forceDebug) console.log(
|
|
619
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning check failed for ${currentUrl}: ${error.message}`));
|
|
573
620
|
}
|
|
574
621
|
|
|
575
622
|
return result;
|
|
@@ -602,7 +649,7 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
602
649
|
};
|
|
603
650
|
|
|
604
651
|
try {
|
|
605
|
-
if (forceDebug) console.log(
|
|
652
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checking for verification challenge on ${currentUrl}`));
|
|
606
653
|
|
|
607
654
|
// Reduced wait time
|
|
608
655
|
await waitForTimeout(page, FAST_TIMEOUTS.CHALLENGE_WAIT);
|
|
@@ -614,27 +661,27 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
614
661
|
result.attempted = true;
|
|
615
662
|
|
|
616
663
|
if (forceDebug) {
|
|
617
|
-
console.log(
|
|
618
|
-
console.log(`
|
|
619
|
-
console.log(`
|
|
620
|
-
console.log(`
|
|
621
|
-
console.log(`
|
|
622
|
-
console.log(`
|
|
623
|
-
console.log(`
|
|
624
|
-
console.log(`
|
|
625
|
-
console.log(`
|
|
626
|
-
console.log(`
|
|
627
|
-
console.log(`
|
|
628
|
-
console.log(`
|
|
629
|
-
console.log(`
|
|
630
|
-
console.log(`
|
|
664
|
+
console.log(formatLogMessage('cloudflare', `Challenge detected on ${currentUrl}:`));
|
|
665
|
+
console.log(formatLogMessage('cloudflare', ` Page Title: "${challengeInfo.title}"`));
|
|
666
|
+
console.log(formatLogMessage('cloudflare', ` Current URL: ${challengeInfo.url}`));
|
|
667
|
+
console.log(formatLogMessage('cloudflare', ` Is Turnstile: ${challengeInfo.isTurnstile}`));
|
|
668
|
+
console.log(formatLogMessage('cloudflare', ` Is JS Challenge: ${challengeInfo.isJSChallenge}`));
|
|
669
|
+
console.log(formatLogMessage('cloudflare', ` Has Legacy Checkbox: ${challengeInfo.hasLegacyCheckbox}`));
|
|
670
|
+
console.log(formatLogMessage('cloudflare', ` Has Turnstile Iframe: ${challengeInfo.hasTurnstileIframe}`));
|
|
671
|
+
console.log(formatLogMessage('cloudflare', ` Has Turnstile Container: ${challengeInfo.hasTurnstileContainer}`));
|
|
672
|
+
console.log(formatLogMessage('cloudflare', ` Has Turnstile Checkbox: ${challengeInfo.hasTurnstileCheckbox}`));
|
|
673
|
+
console.log(formatLogMessage('cloudflare', ` Has CAPTCHA: ${challengeInfo.hasCaptcha}`));
|
|
674
|
+
console.log(formatLogMessage('cloudflare', ` Has Challenge Running: ${challengeInfo.hasChallengeRunning}`));
|
|
675
|
+
console.log(formatLogMessage('cloudflare', ` Has Data Ray: ${challengeInfo.hasDataRay}`));
|
|
676
|
+
console.log(formatLogMessage('cloudflare', ` Has Turnstile Response: ${challengeInfo.hasTurnstileResponse}`));
|
|
677
|
+
console.log(formatLogMessage('cloudflare', ` Body snippet: ${challengeInfo.bodySnippet}`));
|
|
631
678
|
}
|
|
632
679
|
|
|
633
680
|
// Check for CAPTCHA that requires human intervention
|
|
634
681
|
if (challengeInfo.hasCaptcha) {
|
|
635
682
|
result.requiresHuman = true;
|
|
636
683
|
result.error = 'CAPTCHA detected - requires human intervention';
|
|
637
|
-
if (forceDebug) console.log(
|
|
684
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Skipping automatic bypass due to CAPTCHA requirement`));
|
|
638
685
|
return result;
|
|
639
686
|
}
|
|
640
687
|
|
|
@@ -645,17 +692,196 @@ async function handleVerificationChallenge(page, currentUrl, forceDebug = false)
|
|
|
645
692
|
result.method = solveResult.method;
|
|
646
693
|
|
|
647
694
|
} else {
|
|
648
|
-
if (forceDebug) console.log(
|
|
695
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `No verification challenge detected on ${currentUrl}`));
|
|
649
696
|
result.success = true;
|
|
650
697
|
}
|
|
651
698
|
} catch (error) {
|
|
652
699
|
result.error = error.message;
|
|
653
|
-
if (forceDebug) console.log(
|
|
700
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge check failed for ${currentUrl}: ${error.message}`));
|
|
654
701
|
}
|
|
655
702
|
|
|
656
703
|
return result;
|
|
657
704
|
}
|
|
658
705
|
|
|
706
|
+
/**
|
|
707
|
+
* Enhanced challenge handling with retry logic and loop detection
|
|
708
|
+
*/
|
|
709
|
+
async function handleVerificationChallengeWithRetries(page, currentUrl, siteConfig, forceDebug = false) {
|
|
710
|
+
const retryConfig = getRetryConfig(siteConfig);
|
|
711
|
+
const visitedUrls = []; // Track URLs to detect redirect loops
|
|
712
|
+
let lastError = null;
|
|
713
|
+
|
|
714
|
+
if (forceDebug) {
|
|
715
|
+
console.log(formatLogMessage('cloudflare', `Starting verification challenge with max ${retryConfig.maxAttempts} attempts`));
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt++) {
|
|
719
|
+
try {
|
|
720
|
+
const currentPageUrl = await page.url();
|
|
721
|
+
visitedUrls.push(currentPageUrl);
|
|
722
|
+
|
|
723
|
+
// Check for redirect loops
|
|
724
|
+
if (detectChallengeLoop(currentPageUrl, visitedUrls)) {
|
|
725
|
+
const error = `Challenge redirect loop detected after ${attempt} attempts. URLs: ${visitedUrls.slice(-3).join(' -> ')}`;
|
|
726
|
+
if (forceDebug) {
|
|
727
|
+
console.log(formatLogMessage('cloudflare', error));
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
success: false,
|
|
731
|
+
attempted: true,
|
|
732
|
+
error: error,
|
|
733
|
+
details: null,
|
|
734
|
+
requiresHuman: false,
|
|
735
|
+
method: null,
|
|
736
|
+
attempts: attempt,
|
|
737
|
+
loopDetected: true
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
if (forceDebug && attempt > 1) {
|
|
742
|
+
console.log(formatLogMessage('cloudflare', `Challenge attempt ${attempt}/${retryConfig.maxAttempts} for ${currentUrl}`));
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
const result = await handleVerificationChallenge(page, currentUrl, forceDebug);
|
|
746
|
+
|
|
747
|
+
if (result.success || result.requiresHuman || !retryConfig.retryOnError) {
|
|
748
|
+
if (forceDebug && attempt > 1) {
|
|
749
|
+
console.log(`[debug][cloudflare] Challenge ${result.success ? 'succeeded' : 'failed'} on attempt ${attempt}`);
|
|
750
|
+
}
|
|
751
|
+
return { ...result, attempts: attempt };
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// If this wasn't the last attempt, wait before retrying
|
|
755
|
+
if (attempt < retryConfig.maxAttempts) {
|
|
756
|
+
const delay = await getRetryDelay(attempt);
|
|
757
|
+
if (forceDebug) {
|
|
758
|
+
console.log(formatLogMessage('cloudflare', `Challenge attempt ${attempt} failed, retrying in ${delay}ms: ${result.error}`));
|
|
759
|
+
}
|
|
760
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
761
|
+
|
|
762
|
+
// Refresh the page to get a fresh challenge
|
|
763
|
+
try {
|
|
764
|
+
await page.reload({ waitUntil: 'domcontentloaded', timeout: 10000 });
|
|
765
|
+
await waitForTimeout(page, 2000); // Give challenge time to load
|
|
766
|
+
} catch (reloadErr) {
|
|
767
|
+
if (forceDebug) {
|
|
768
|
+
console.log(formatLogMessage('cloudflare', `Page reload failed on attempt ${attempt}: ${reloadErr.message}`));
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
lastError = result.error;
|
|
774
|
+
} catch (error) {
|
|
775
|
+
lastError = error.message;
|
|
776
|
+
const errorType = categorizeError(error);
|
|
777
|
+
|
|
778
|
+
if (forceDebug) {
|
|
779
|
+
console.warn(formatLogMessage('cloudflare', `Challenge attempt ${attempt}/${retryConfig.maxAttempts} failed: ${error.message} [${errorType}]`));
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
// Don't retry if error type is not retryable or if it's the last attempt
|
|
783
|
+
if (!retryConfig.retryableErrors.includes(errorType) || attempt === retryConfig.maxAttempts) {
|
|
784
|
+
return {
|
|
785
|
+
success: false,
|
|
786
|
+
attempted: true,
|
|
787
|
+
error: lastError,
|
|
788
|
+
details: null,
|
|
789
|
+
requiresHuman: false,
|
|
790
|
+
method: null,
|
|
791
|
+
attempts: attempt,
|
|
792
|
+
errorType: errorType
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
// Wait before retrying with exponential backoff
|
|
797
|
+
if (attempt < retryConfig.maxAttempts) {
|
|
798
|
+
await getRetryDelay(attempt);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
return {
|
|
804
|
+
success: false,
|
|
805
|
+
attempted: true,
|
|
806
|
+
error: `All ${retryConfig.maxAttempts} challenge attempts failed. Last error: ${lastError}`,
|
|
807
|
+
details: null,
|
|
808
|
+
requiresHuman: false,
|
|
809
|
+
method: null,
|
|
810
|
+
attempts: retryConfig.maxAttempts,
|
|
811
|
+
maxRetriesExceeded: true
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
/**
|
|
816
|
+
* Enhanced phishing warning handling with retry logic
|
|
817
|
+
*/
|
|
818
|
+
async function handlePhishingWarningWithRetries(page, currentUrl, siteConfig, forceDebug = false) {
|
|
819
|
+
const retryConfig = getRetryConfig(siteConfig);
|
|
820
|
+
let lastError = null;
|
|
821
|
+
|
|
822
|
+
for (let attempt = 1; attempt <= retryConfig.maxAttempts; attempt++) {
|
|
823
|
+
try {
|
|
824
|
+
if (forceDebug && attempt > 1) {
|
|
825
|
+
console.log(formatLogMessage('cloudflare', `Phishing warning attempt ${attempt}/${retryConfig.maxAttempts} for ${currentUrl}`));
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
const result = await handlePhishingWarning(page, currentUrl, forceDebug);
|
|
829
|
+
|
|
830
|
+
if (result.success || !retryConfig.retryOnError) {
|
|
831
|
+
if (forceDebug && attempt > 1) {
|
|
832
|
+
console.log(`[debug][cloudflare] Phishing warning ${result.success ? 'succeeded' : 'failed'} on attempt ${attempt}`);
|
|
833
|
+
}
|
|
834
|
+
return { ...result, attempts: attempt };
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// If this wasn't the last attempt, wait before retrying
|
|
838
|
+
if (attempt < retryConfig.maxAttempts) {
|
|
839
|
+
const delay = await getRetryDelay(attempt);
|
|
840
|
+
if (forceDebug) {
|
|
841
|
+
console.log(formatLogMessage('cloudflare', `Phishing warning attempt ${attempt} failed, retrying in ${delay}ms: ${result.error}`));
|
|
842
|
+
}
|
|
843
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
lastError = result.error;
|
|
847
|
+
} catch (error) {
|
|
848
|
+
lastError = error.message;
|
|
849
|
+
const errorType = categorizeError(error);
|
|
850
|
+
|
|
851
|
+
if (forceDebug) {
|
|
852
|
+
console.warn(formatLogMessage('cloudflare', `Phishing warning attempt ${attempt}/${retryConfig.maxAttempts} failed: ${error.message} [${errorType}]`));
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// Don't retry if error type is not retryable or if it's the last attempt
|
|
856
|
+
if (!retryConfig.retryableErrors.includes(errorType) || attempt === retryConfig.maxAttempts) {
|
|
857
|
+
return {
|
|
858
|
+
success: false,
|
|
859
|
+
attempted: true,
|
|
860
|
+
error: lastError,
|
|
861
|
+
details: null,
|
|
862
|
+
attempts: attempt,
|
|
863
|
+
errorType: errorType
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
// Wait before retrying with exponential backoff
|
|
868
|
+
if (attempt < retryConfig.maxAttempts) {
|
|
869
|
+
await getRetryDelay(attempt);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
return {
|
|
875
|
+
success: false,
|
|
876
|
+
attempted: true,
|
|
877
|
+
error: `All ${retryConfig.maxAttempts} phishing warning attempts failed. Last error: ${lastError}`,
|
|
878
|
+
details: null,
|
|
879
|
+
attempts: retryConfig.maxAttempts,
|
|
880
|
+
maxRetriesExceeded: true
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
|
|
659
885
|
/**
|
|
660
886
|
* Challenge solving with overall timeout protection
|
|
661
887
|
*/
|
|
@@ -676,7 +902,7 @@ async function attemptChallengeSolveWithTimeout(page, currentUrl, challengeInfo,
|
|
|
676
902
|
]);
|
|
677
903
|
} catch (error) {
|
|
678
904
|
result.error = `Challenge solving timed out: ${error.message}`;
|
|
679
|
-
if (forceDebug) console.log(
|
|
905
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge solving timeout for ${currentUrl}`));
|
|
680
906
|
return result;
|
|
681
907
|
}
|
|
682
908
|
}
|
|
@@ -694,51 +920,51 @@ async function attemptChallengeSolve(page, currentUrl, challengeInfo, forceDebug
|
|
|
694
920
|
// Method 1: Handle JS challenges (wait for automatic completion) - Most reliable
|
|
695
921
|
if (challengeInfo.isJSChallenge) {
|
|
696
922
|
try {
|
|
697
|
-
if (forceDebug) console.log(
|
|
923
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Attempting JS challenge wait for ${currentUrl}`));
|
|
698
924
|
|
|
699
925
|
const jsResult = await waitForJSChallengeCompletion(page, forceDebug);
|
|
700
926
|
if (jsResult.success) {
|
|
701
927
|
result.success = true;
|
|
702
928
|
result.method = 'js_challenge_wait';
|
|
703
|
-
if (forceDebug) console.log(
|
|
929
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `JS challenge completed successfully for ${currentUrl}`));
|
|
704
930
|
return result;
|
|
705
931
|
}
|
|
706
932
|
} catch (jsError) {
|
|
707
|
-
if (forceDebug) console.log(
|
|
933
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `JS challenge wait failed for ${currentUrl}: ${jsError.message}`));
|
|
708
934
|
}
|
|
709
935
|
}
|
|
710
936
|
|
|
711
937
|
// Method 2: Handle Turnstile challenges (interactive)
|
|
712
938
|
if (challengeInfo.isTurnstile) {
|
|
713
939
|
try {
|
|
714
|
-
if (forceDebug) console.log(
|
|
940
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Attempting Turnstile method for ${currentUrl}`));
|
|
715
941
|
|
|
716
942
|
const turnstileResult = await handleTurnstileChallenge(page, forceDebug);
|
|
717
943
|
if (turnstileResult.success) {
|
|
718
944
|
result.success = true;
|
|
719
945
|
result.method = 'turnstile';
|
|
720
|
-
if (forceDebug) console.log(
|
|
946
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Turnstile challenge solved successfully for ${currentUrl}`));
|
|
721
947
|
return result;
|
|
722
948
|
}
|
|
723
949
|
} catch (turnstileError) {
|
|
724
|
-
if (forceDebug) console.log(
|
|
950
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Turnstile method failed for ${currentUrl}: ${turnstileError.message}`));
|
|
725
951
|
}
|
|
726
952
|
}
|
|
727
953
|
|
|
728
954
|
// Method 3: Legacy checkbox interaction (fallback)
|
|
729
955
|
if (challengeInfo.hasLegacyCheckbox) {
|
|
730
956
|
try {
|
|
731
|
-
if (forceDebug) console.log(
|
|
957
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Attempting legacy checkbox method for ${currentUrl}`));
|
|
732
958
|
|
|
733
959
|
const legacyResult = await handleLegacyCheckbox(page, forceDebug);
|
|
734
960
|
if (legacyResult.success) {
|
|
735
961
|
result.success = true;
|
|
736
962
|
result.method = 'legacy_checkbox';
|
|
737
|
-
if (forceDebug) console.log(
|
|
963
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Legacy checkbox method succeeded for ${currentUrl}`));
|
|
738
964
|
return result;
|
|
739
965
|
}
|
|
740
966
|
} catch (legacyError) {
|
|
741
|
-
if (forceDebug) console.log(
|
|
967
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Legacy checkbox method failed for ${currentUrl}: ${legacyError.message}`));
|
|
742
968
|
}
|
|
743
969
|
}
|
|
744
970
|
|
|
@@ -759,7 +985,7 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
759
985
|
};
|
|
760
986
|
|
|
761
987
|
try {
|
|
762
|
-
if (forceDebug) console.log(
|
|
988
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checking for embedded iframe challenges`));
|
|
763
989
|
|
|
764
990
|
// Enhanced iframe selectors including challenges.cloudflare.com
|
|
765
991
|
const iframeSelectors = [
|
|
@@ -778,7 +1004,7 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
778
1004
|
new Promise((_, reject) => setTimeout(() => reject(new Error('Timeout')), FAST_TIMEOUTS.SELECTOR_WAIT + 1000))
|
|
779
1005
|
]);
|
|
780
1006
|
iframeFound = true;
|
|
781
|
-
if (forceDebug) console.log(
|
|
1007
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Found iframe: ${selector}`));
|
|
782
1008
|
break;
|
|
783
1009
|
} catch (e) {
|
|
784
1010
|
continue;
|
|
@@ -806,7 +1032,7 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
806
1032
|
return result;
|
|
807
1033
|
}
|
|
808
1034
|
|
|
809
|
-
if (forceDebug) console.log(
|
|
1035
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Interacting with iframe: ${challengeFrame.url()}`));
|
|
810
1036
|
|
|
811
1037
|
// Reuse existing checkbox interaction logic
|
|
812
1038
|
const checkboxSelectors = [
|
|
@@ -828,7 +1054,7 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
828
1054
|
await waitForTimeout(page, FAST_TIMEOUTS.ELEMENT_INTERACTION_DELAY);
|
|
829
1055
|
await challengeFrame.click(selector);
|
|
830
1056
|
|
|
831
|
-
if (forceDebug) console.log(
|
|
1057
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Clicked iframe element: ${selector}`));
|
|
832
1058
|
checkboxInteractionSuccess = true;
|
|
833
1059
|
break;
|
|
834
1060
|
} catch (e) {
|
|
@@ -838,7 +1064,7 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
838
1064
|
|
|
839
1065
|
// Try alternative interaction only if standard selectors failed
|
|
840
1066
|
if (!checkboxInteractionSuccess) {
|
|
841
|
-
if (forceDebug) console.log(
|
|
1067
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checkbox interactions failed, trying container fallback`));
|
|
842
1068
|
await waitForTimeout(page, 1000);
|
|
843
1069
|
|
|
844
1070
|
try {
|
|
@@ -846,13 +1072,13 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
846
1072
|
const iframeElement = await page.$('iframe[src*="challenges.cloudflare.com"]');
|
|
847
1073
|
if (iframeElement) {
|
|
848
1074
|
await iframeElement.click();
|
|
849
|
-
if (forceDebug) console.log(
|
|
1075
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Clicked iframe container as fallback`));
|
|
850
1076
|
}
|
|
851
1077
|
} catch (containerClickError) {
|
|
852
|
-
if (forceDebug) console.log(
|
|
1078
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Container click failed: ${containerClickError.message}`));
|
|
853
1079
|
}
|
|
854
1080
|
} else {
|
|
855
|
-
if (forceDebug) console.log(
|
|
1081
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checkbox interaction successful, skipping container fallback`));
|
|
856
1082
|
}
|
|
857
1083
|
|
|
858
1084
|
// Reuse existing completion check pattern with error handling
|
|
@@ -873,15 +1099,15 @@ async function handleEmbeddedIframeChallenge(page, forceDebug = false) {
|
|
|
873
1099
|
]);
|
|
874
1100
|
|
|
875
1101
|
result.success = true;
|
|
876
|
-
if (forceDebug) console.log(
|
|
1102
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Embedded iframe challenge completed`));
|
|
877
1103
|
} catch (completionError) {
|
|
878
1104
|
result.error = `Challenge completion check failed: ${completionError.message}`;
|
|
879
|
-
if (forceDebug) console.log(
|
|
1105
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Completion check failed: ${completionError.message}`));
|
|
880
1106
|
}
|
|
881
1107
|
|
|
882
1108
|
} catch (error) {
|
|
883
1109
|
result.error = `Embedded iframe handling failed: ${error.message}`;
|
|
884
|
-
if (forceDebug) console.log(
|
|
1110
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', result.error));
|
|
885
1111
|
}
|
|
886
1112
|
|
|
887
1113
|
return result;
|
|
@@ -897,7 +1123,7 @@ async function waitForJSChallengeCompletion(page, forceDebug = false) {
|
|
|
897
1123
|
};
|
|
898
1124
|
|
|
899
1125
|
try {
|
|
900
|
-
if (forceDebug) console.log(
|
|
1126
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Waiting for JS challenge completion`));
|
|
901
1127
|
|
|
902
1128
|
// Reduced timeout for JS challenge completion
|
|
903
1129
|
await Promise.race([
|
|
@@ -916,10 +1142,10 @@ async function waitForJSChallengeCompletion(page, forceDebug = false) {
|
|
|
916
1142
|
]);
|
|
917
1143
|
|
|
918
1144
|
result.success = true;
|
|
919
|
-
if (forceDebug) console.log(
|
|
1145
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `JS challenge completed automatically`));
|
|
920
1146
|
} catch (error) {
|
|
921
1147
|
result.error = `JS challenge timeout: ${error.message}`;
|
|
922
|
-
if (forceDebug) console.log(
|
|
1148
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `JS challenge wait failed: ${error.message}`));
|
|
923
1149
|
}
|
|
924
1150
|
|
|
925
1151
|
return result;
|
|
@@ -940,7 +1166,7 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
940
1166
|
return { ...result, success: true };
|
|
941
1167
|
}
|
|
942
1168
|
|
|
943
|
-
if (forceDebug) console.log(
|
|
1169
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Embedded iframe failed: ${iframeResult.error}, trying legacy method`));
|
|
944
1170
|
|
|
945
1171
|
try {
|
|
946
1172
|
// Use fast timeout for Turnstile operations
|
|
@@ -966,18 +1192,18 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
966
1192
|
frame.url().includes('turnstile')
|
|
967
1193
|
);
|
|
968
1194
|
if (turnstileFrame) {
|
|
969
|
-
if (forceDebug) console.log(
|
|
1195
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Found Turnstile iframe using selector: ${selector}`));
|
|
970
1196
|
break;
|
|
971
1197
|
}
|
|
972
1198
|
} catch (e) {
|
|
973
|
-
if (forceDebug) console.log(
|
|
1199
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Selector ${selector} not found or timed out`));
|
|
974
1200
|
continue;
|
|
975
1201
|
}
|
|
976
1202
|
}
|
|
977
1203
|
|
|
978
1204
|
if (turnstileFrame) {
|
|
979
1205
|
if (forceDebug) {
|
|
980
|
-
console.log(
|
|
1206
|
+
console.log(formatLogMessage('cloudflare', `Found Turnstile iframe with URL: ${turnstileFrame.url()}`));
|
|
981
1207
|
}
|
|
982
1208
|
|
|
983
1209
|
const checkboxSelectors = [
|
|
@@ -997,10 +1223,10 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
997
1223
|
await waitForTimeout(page, FAST_TIMEOUTS.ELEMENT_INTERACTION_DELAY);
|
|
998
1224
|
await turnstileFrame.click(selector);
|
|
999
1225
|
|
|
1000
|
-
if (forceDebug) console.log(
|
|
1226
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Clicked Turnstile checkbox: ${selector}`));
|
|
1001
1227
|
break;
|
|
1002
1228
|
} catch (e) {
|
|
1003
|
-
if (forceDebug) console.log(
|
|
1229
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Checkbox selector ${selector} not found or failed to click`));
|
|
1004
1230
|
continue;
|
|
1005
1231
|
}
|
|
1006
1232
|
}
|
|
@@ -1017,11 +1243,11 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
1017
1243
|
new Promise((_, reject) => setTimeout(() => reject(new Error('Turnstile completion timeout')), TIMEOUTS.TURNSTILE_COMPLETION_BUFFER))
|
|
1018
1244
|
]);
|
|
1019
1245
|
|
|
1020
|
-
if (forceDebug) console.log(
|
|
1246
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Turnstile response token generated successfully`));
|
|
1021
1247
|
result.success = true;
|
|
1022
1248
|
} else {
|
|
1023
1249
|
// Try container-based Turnstile (non-iframe)
|
|
1024
|
-
if (forceDebug) console.log(
|
|
1250
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `No Turnstile iframe found, trying container-based approach`));
|
|
1025
1251
|
|
|
1026
1252
|
const containerSelectors = [
|
|
1027
1253
|
'.cf-turnstile',
|
|
@@ -1039,29 +1265,29 @@ async function handleTurnstileChallenge(page, forceDebug = false) {
|
|
|
1039
1265
|
await waitForTimeout(page, FAST_TIMEOUTS.ELEMENT_INTERACTION_DELAY);
|
|
1040
1266
|
await page.click(selector);
|
|
1041
1267
|
|
|
1042
|
-
if (forceDebug) console.log(
|
|
1268
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Clicked Turnstile container: ${selector}`));
|
|
1043
1269
|
|
|
1044
1270
|
const completionCheck = await checkChallengeCompletion(page);
|
|
1045
1271
|
if (completionCheck.isCompleted) {
|
|
1046
1272
|
result.success = true;
|
|
1047
|
-
if (forceDebug) console.log(
|
|
1273
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Container-based Turnstile completed successfully`));
|
|
1048
1274
|
break;
|
|
1049
1275
|
}
|
|
1050
1276
|
} catch (e) {
|
|
1051
|
-
if (forceDebug) console.log(
|
|
1277
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Container selector ${selector} not found or failed`));
|
|
1052
1278
|
continue;
|
|
1053
1279
|
}
|
|
1054
1280
|
}
|
|
1055
1281
|
|
|
1056
1282
|
if (!result.success) {
|
|
1057
1283
|
result.error = 'Turnstile iframe/container not found or not interactive';
|
|
1058
|
-
if (forceDebug) console.log(
|
|
1284
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', result.error));
|
|
1059
1285
|
}
|
|
1060
1286
|
}
|
|
1061
1287
|
|
|
1062
1288
|
} catch (error) {
|
|
1063
1289
|
result.error = `Turnstile handling failed: ${error.message}`;
|
|
1064
|
-
if (forceDebug) console.log(
|
|
1290
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Turnstile handling error: ${error.message}`));
|
|
1065
1291
|
}
|
|
1066
1292
|
|
|
1067
1293
|
return result;
|
|
@@ -1077,7 +1303,7 @@ async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
|
1077
1303
|
};
|
|
1078
1304
|
|
|
1079
1305
|
try {
|
|
1080
|
-
if (forceDebug) console.log(
|
|
1306
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Attempting legacy checkbox challenge`));
|
|
1081
1307
|
|
|
1082
1308
|
const legacySelectors = [
|
|
1083
1309
|
'input[type="checkbox"]#challenge-form',
|
|
@@ -1095,29 +1321,29 @@ async function handleLegacyCheckbox(page, forceDebug = false) {
|
|
|
1095
1321
|
const checkbox = await page.$(selector);
|
|
1096
1322
|
if (checkbox) {
|
|
1097
1323
|
await checkbox.click();
|
|
1098
|
-
if (forceDebug) console.log(
|
|
1324
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Clicked legacy checkbox: ${selector}`));
|
|
1099
1325
|
|
|
1100
1326
|
const completionCheck = await checkChallengeCompletion(page);
|
|
1101
1327
|
if (completionCheck.isCompleted) {
|
|
1102
1328
|
result.success = true;
|
|
1103
|
-
if (forceDebug) console.log(
|
|
1329
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Legacy checkbox challenge completed successfully`));
|
|
1104
1330
|
break;
|
|
1105
1331
|
}
|
|
1106
1332
|
}
|
|
1107
1333
|
} catch (e) {
|
|
1108
|
-
if (forceDebug) console.log(
|
|
1334
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Legacy selector ${selector} failed: ${e.message}`));
|
|
1109
1335
|
continue;
|
|
1110
1336
|
}
|
|
1111
1337
|
}
|
|
1112
1338
|
|
|
1113
1339
|
if (!result.success) {
|
|
1114
1340
|
result.error = 'No interactive legacy checkbox found';
|
|
1115
|
-
if (forceDebug) console.log(
|
|
1341
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', result.error));
|
|
1116
1342
|
}
|
|
1117
1343
|
|
|
1118
1344
|
} catch (error) {
|
|
1119
1345
|
result.error = `Legacy checkbox handling failed: ${error.message}`;
|
|
1120
|
-
if (forceDebug) console.log(
|
|
1346
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Legacy checkbox error: ${error.message}`));
|
|
1121
1347
|
}
|
|
1122
1348
|
|
|
1123
1349
|
return result;
|
|
@@ -1191,13 +1417,13 @@ async function checkChallengeCompletion(page) {
|
|
|
1191
1417
|
*/
|
|
1192
1418
|
async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDebug = false) {
|
|
1193
1419
|
if (forceDebug) {
|
|
1194
|
-
console.log(
|
|
1420
|
+
console.log(formatLogMessage('cloudflare', `Using Cloudflare module v${CLOUDFLARE_MODULE_VERSION} for ${currentUrl}`));
|
|
1195
1421
|
}
|
|
1196
1422
|
|
|
1197
1423
|
// VALIDATE URL FIRST - Skip protection handling for non-HTTP(S) URLs
|
|
1198
1424
|
if (!shouldProcessUrl(currentUrl, forceDebug)) {
|
|
1199
1425
|
if (forceDebug) {
|
|
1200
|
-
console.log(
|
|
1426
|
+
console.log(formatLogMessage('cloudflare', `Skipping protection handling for non-HTTP(S) URL: ${currentUrl}`));
|
|
1201
1427
|
}
|
|
1202
1428
|
return {
|
|
1203
1429
|
phishingWarning: { attempted: false, success: true },
|
|
@@ -1216,8 +1442,8 @@ async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDeb
|
|
|
1216
1442
|
|
|
1217
1443
|
// Only proceed if we have indicators OR explicit config enables Cloudflare handling
|
|
1218
1444
|
if (!quickDetection.hasIndicators && !siteConfig.cloudflare_phish && !siteConfig.cloudflare_bypass) {
|
|
1219
|
-
if (forceDebug) console.log(
|
|
1220
|
-
if (forceDebug) console.log(
|
|
1445
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `No Cloudflare indicators found and no explicit config, skipping protection handling for ${currentUrl}`));
|
|
1446
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Quick detection details: title="${quickDetection.title}", bodySnippet="${quickDetection.bodySnippet}"`));
|
|
1221
1447
|
return {
|
|
1222
1448
|
phishingWarning: { attempted: false, success: true },
|
|
1223
1449
|
verificationChallenge: { attempted: false, success: true },
|
|
@@ -1249,14 +1475,14 @@ async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDeb
|
|
|
1249
1475
|
}
|
|
1250
1476
|
|
|
1251
1477
|
if (forceDebug) {
|
|
1252
|
-
console.log(
|
|
1478
|
+
console.log(formatLogMessage('cloudflare', `Using adaptive timeout of ${adaptiveTimeout}ms for ${currentUrl} (indicators: ${quickDetection.hasIndicators}, explicit config: ${!!(siteConfig.cloudflare_phish || siteConfig.cloudflare_bypass)})`));
|
|
1253
1479
|
}
|
|
1254
1480
|
|
|
1255
1481
|
return await Promise.race([
|
|
1256
1482
|
performCloudflareHandling(page, currentUrl, siteConfig, forceDebug),
|
|
1257
1483
|
new Promise((resolve) => {
|
|
1258
1484
|
setTimeout(() => {
|
|
1259
|
-
console.warn(
|
|
1485
|
+
console.warn(formatLogMessage('cloudflare', `Adaptive timeout (${adaptiveTimeout}ms) for ${currentUrl} - continuing with scan`));
|
|
1260
1486
|
resolve({
|
|
1261
1487
|
phishingWarning: { attempted: false, success: true },
|
|
1262
1488
|
verificationChallenge: { attempted: false, success: true },
|
|
@@ -1270,7 +1496,7 @@ async function handleCloudflareProtection(page, currentUrl, siteConfig, forceDeb
|
|
|
1270
1496
|
} catch (error) {
|
|
1271
1497
|
result.overallSuccess = false;
|
|
1272
1498
|
result.errors.push(`Cloudflare handling failed: ${error.message}`);
|
|
1273
|
-
if (forceDebug) console.log(
|
|
1499
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Overall handling failed: ${error.message}`));
|
|
1274
1500
|
return result;
|
|
1275
1501
|
}
|
|
1276
1502
|
}
|
|
@@ -1292,26 +1518,40 @@ async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebu
|
|
|
1292
1518
|
errors: []
|
|
1293
1519
|
};
|
|
1294
1520
|
|
|
1295
|
-
if (forceDebug) console.log(
|
|
1521
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Starting Cloudflare protection handling for ${currentUrl}`));
|
|
1296
1522
|
|
|
1297
1523
|
// Handle phishing warnings first - updates result.phishingWarning
|
|
1298
1524
|
// Only runs if siteConfig.cloudflare_phish === true
|
|
1299
1525
|
// Handle phishing warnings if enabled
|
|
1300
1526
|
if (siteConfig.cloudflare_phish === true) {
|
|
1301
|
-
if (forceDebug) console.log(
|
|
1527
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning bypass enabled for ${currentUrl}`));
|
|
1302
1528
|
|
|
1303
|
-
const phishingResult = await
|
|
1529
|
+
const phishingResult = await handlePhishingWarningWithRetries(page, currentUrl, siteConfig, forceDebug);
|
|
1304
1530
|
result.phishingWarning = phishingResult;
|
|
1531
|
+
|
|
1532
|
+
// Check for max retries exceeded
|
|
1533
|
+
if (phishingResult.maxRetriesExceeded) {
|
|
1534
|
+
result.overallSuccess = false;
|
|
1535
|
+
result.errors.push(`Phishing warning bypass exceeded max retries (${phishingResult.attempts}): ${phishingResult.error}`);
|
|
1536
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning max retries exceeded: ${phishingResult.error}`));
|
|
1537
|
+
// Exit early if max retries exceeded
|
|
1538
|
+
return result;
|
|
1539
|
+
}
|
|
1305
1540
|
|
|
1306
1541
|
if (phishingResult.attempted && !phishingResult.success) {
|
|
1307
1542
|
result.overallSuccess = false;
|
|
1308
|
-
|
|
1309
|
-
|
|
1543
|
+
if (phishingResult.loopDetected) {
|
|
1544
|
+
result.errors.push(`Phishing warning bypass failed (redirect loop): ${phishingResult.error}`);
|
|
1545
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning redirect loop detected: ${phishingResult.error}`));
|
|
1546
|
+
} else {
|
|
1547
|
+
result.errors.push(`Phishing warning bypass failed: ${phishingResult.error}`);
|
|
1548
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning handling failed: ${phishingResult.error}`));
|
|
1549
|
+
}
|
|
1310
1550
|
} else if (phishingResult.attempted && phishingResult.success) {
|
|
1311
|
-
if (forceDebug) console.log(
|
|
1551
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Phishing warning handled successfully`));
|
|
1312
1552
|
}
|
|
1313
1553
|
} else if (forceDebug) {
|
|
1314
|
-
console.log(
|
|
1554
|
+
console.log(formatLogMessage('cloudflare', `Phishing warning bypass disabled for ${currentUrl}`));
|
|
1315
1555
|
}
|
|
1316
1556
|
|
|
1317
1557
|
// Handle verification challenges second - updates result.verificationChallenge
|
|
@@ -1319,37 +1559,49 @@ async function performCloudflareHandling(page, currentUrl, siteConfig, forceDebu
|
|
|
1319
1559
|
// Sets requiresHuman: true if CAPTCHA detected (no bypass attempted)
|
|
1320
1560
|
// Handle verification challenges if enabled
|
|
1321
1561
|
if (siteConfig.cloudflare_bypass === true) {
|
|
1322
|
-
if (forceDebug) console.log(
|
|
1562
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge bypass enabled for ${currentUrl}`));
|
|
1323
1563
|
|
|
1324
|
-
const challengeResult = await
|
|
1564
|
+
const challengeResult = await handleVerificationChallengeWithRetries(page, currentUrl, siteConfig, forceDebug);
|
|
1325
1565
|
result.verificationChallenge = challengeResult;
|
|
1566
|
+
|
|
1567
|
+
// Check for max retries exceeded
|
|
1568
|
+
if (challengeResult.maxRetriesExceeded) {
|
|
1569
|
+
result.overallSuccess = false;
|
|
1570
|
+
result.errors.push(`Challenge bypass exceeded max retries (${challengeResult.attempts}): ${challengeResult.error}`);
|
|
1571
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge bypass max retries exceeded: ${challengeResult.error}`));
|
|
1572
|
+
// Exit early if max retries exceeded
|
|
1573
|
+
return result;
|
|
1574
|
+
}
|
|
1326
1575
|
|
|
1327
1576
|
if (challengeResult.attempted && !challengeResult.success) {
|
|
1328
1577
|
result.overallSuccess = false;
|
|
1329
1578
|
if (challengeResult.requiresHuman) {
|
|
1330
1579
|
result.errors.push(`Human intervention required: ${challengeResult.error}`);
|
|
1331
|
-
if (forceDebug) console.log(
|
|
1580
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Human intervention required: ${challengeResult.error}`));
|
|
1581
|
+
} else if (challengeResult.loopDetected) {
|
|
1582
|
+
result.errors.push(`Challenge bypass failed (redirect loop): ${challengeResult.error}`);
|
|
1583
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge redirect loop detected: ${challengeResult.error}`));
|
|
1332
1584
|
} else {
|
|
1333
1585
|
result.errors.push(`Challenge bypass failed: ${challengeResult.error}`);
|
|
1334
|
-
if (forceDebug) console.log(
|
|
1586
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge bypass failed: ${challengeResult.error}`));
|
|
1335
1587
|
}
|
|
1336
1588
|
} else if (challengeResult.attempted && challengeResult.success) {
|
|
1337
|
-
if (forceDebug) console.log(
|
|
1589
|
+
if (forceDebug) console.log(formatLogMessage('cloudflare', `Challenge handled successfully using method: ${challengeResult.method || 'unknown'}`));
|
|
1338
1590
|
}
|
|
1339
1591
|
} else if (forceDebug) {
|
|
1340
|
-
|
|
1592
|
+
console.log(formatLogMessage('cloudflare', `Challenge bypass disabled for ${currentUrl}`));
|
|
1341
1593
|
}
|
|
1342
1594
|
|
|
1343
1595
|
// Log overall result
|
|
1344
1596
|
if (!result.overallSuccess && forceDebug) {
|
|
1345
|
-
console.log(
|
|
1597
|
+
console.log(formatLogMessage('cloudflare', `Overall Cloudflare handling failed for ${currentUrl}:`));
|
|
1346
1598
|
result.errors.forEach(error => {
|
|
1347
|
-
console.log(`
|
|
1599
|
+
console.log(formatLogMessage('cloudflare', ` - ${error}`));
|
|
1348
1600
|
});
|
|
1349
1601
|
} else if ((result.phishingWarning.attempted || result.verificationChallenge.attempted) && forceDebug) {
|
|
1350
|
-
console.log(
|
|
1602
|
+
console.log(formatLogMessage('cloudflare', `Successfully handled Cloudflare protections for ${currentUrl}`));
|
|
1351
1603
|
} else if (forceDebug) {
|
|
1352
|
-
console.log(
|
|
1604
|
+
console.log(formatLogMessage('cloudflare', `No Cloudflare protections detected or enabled for ${currentUrl}`));
|
|
1353
1605
|
}
|
|
1354
1606
|
|
|
1355
1607
|
return result;
|
|
@@ -1412,7 +1664,7 @@ async function parallelChallengeDetection(page, forceDebug = false) {
|
|
|
1412
1664
|
const detectedChallenges = results.filter(r => r.detected).map(r => r.type);
|
|
1413
1665
|
|
|
1414
1666
|
if (forceDebug && detectedChallenges.length > 0) {
|
|
1415
|
-
console.log(
|
|
1667
|
+
console.log(formatLogMessage('cloudflare', `Parallel detection found challenges: ${detectedChallenges.join(', ')}`));
|
|
1416
1668
|
}
|
|
1417
1669
|
|
|
1418
1670
|
return {
|
|
@@ -1480,5 +1732,7 @@ module.exports = {
|
|
|
1480
1732
|
clearDetectionCache,
|
|
1481
1733
|
categorizeError,
|
|
1482
1734
|
ERROR_TYPES,
|
|
1483
|
-
RETRY_CONFIG
|
|
1735
|
+
RETRY_CONFIG,
|
|
1736
|
+
getRetryConfig,
|
|
1737
|
+
detectChallengeLoop
|
|
1484
1738
|
};
|